mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 11:11:37 -07:00
Compare commits
2079 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73beed0477 | |||
| e0ecdd4b24 | |||
| 5168cf03a9 | |||
| b886ae6515 | |||
| 277a973b98 | |||
| 0ec4d97bfd | |||
| e6236e5c3e | |||
| e201280844 | |||
| 8e50a6c61b | |||
| 7e6f5f89d0 | |||
| 97acc57649 | |||
| 83c8c48ed7 | |||
| 0815b4d59f | |||
| a0135080b3 | |||
| f45e8e5d47 | |||
| 98ba4beede | |||
| a9304f2fef | |||
| a0697ab057 | |||
| 2e895c72d3 | |||
| 674ebe395f | |||
| 96eecaab54 | |||
| b1ae5bc9fe | |||
| 7258588ed5 | |||
| d913155972 | |||
| 9746e25784 | |||
| d26cfd2141 | |||
| 21f2c06f4b | |||
| 727a25f41f | |||
| 3f27cb2309 | |||
| f213622982 | |||
| 4aad835a66 | |||
| 4af8a64580 | |||
| c9c3611b1d | |||
| 220dfd7440 | |||
| bce8819ed5 | |||
| 5f2b220a85 | |||
| f174c805a9 | |||
| 25869b7504 | |||
| ecd81e8a53 | |||
| d7f9f7f170 | |||
| 08f5259d77 | |||
| a9f744cb64 | |||
| b02e42c6dc | |||
| cb0273b5d7 | |||
| 8dbf45a65a | |||
| 9f64de9568 | |||
| 0ebe9ba487 | |||
| efe00e1aa6 | |||
| 2bdbce55f9 | |||
| 9614ca92f0 | |||
| d30e59f539 | |||
| a3afe617c2 | |||
| 69daac583e | |||
| b28d4b753b | |||
| e6ab4f4856 | |||
| c8ab1b7ee1 | |||
| 9f10487678 | |||
| 2542983d70 | |||
| d492fb3501 | |||
| 1829aa1638 | |||
| 4cb4173ced | |||
| 00e704b216 | |||
| 227ee0f705 | |||
| 17f47a7ab0 | |||
| 4e8bc0786d | |||
| 3d3ccf061f | |||
| 3a8adc6721 | |||
| e1748a5dd1 | |||
| 59b4c889d3 | |||
| b6408d1b3f | |||
| 3db3047f47 | |||
| 7420fbd95b | |||
| 7c990b3833 | |||
| 9c059f1a12 | |||
| fb167d1d0a | |||
| 0992239d86 | |||
| 9eb3da0474 | |||
| e91f8feedf | |||
| 22a0c3fce1 | |||
| 6c7e5748a8 | |||
| 0b0c6da8b0 | |||
| 78826071c0 | |||
| e61b73d7ad | |||
| f886632bf1 | |||
| eafa5098aa | |||
| 0571b80d37 | |||
| 80c10644dd | |||
| 041625381c | |||
| 48f56d728b | |||
| 872d391cfb | |||
| 3e6ec65dd9 | |||
| 157c87b2a2 | |||
| d3081bd889 | |||
| 2ae5bf4395 | |||
| f28547cae1 | |||
| 5332705e31 | |||
| bfb082cda4 | |||
| 37d04198ab | |||
| ae9d540c1c | |||
| c90b7c38f1 | |||
| 9e376fbda7 | |||
| 00739bf06d | |||
| e8148055ad | |||
| dd0a20ab45 | |||
| babbc304b8 | |||
| a8b44f33bd | |||
| bd48561688 | |||
| 23842a8950 | |||
| 1676c643df | |||
| e2bfb024de | |||
| 4d06a54c0c | |||
| 0a8e6169d7 | |||
| 04ae87eaef | |||
| b313d09c2c | |||
| c0d2359a91 | |||
| 51a2f09032 | |||
| f60e8031f2 | |||
| ea42613fec | |||
| b89bb87759 | |||
| 2cbb3d5a24 | |||
| 9e288b7ce8 | |||
| 776b48c10d | |||
| 199dae6cd5 | |||
| e58f45bef7 | |||
| abe122ecb7 | |||
| f8744d87b0 | |||
| 3e7f6b8751 | |||
| 6ffe814ca7 | |||
| eec9be71f6 | |||
| 888913c739 | |||
| 33d96fd28a | |||
| f1e8738af2 | |||
| 9c52a11b1b | |||
| d89c4606bd | |||
| c6903fbcd5 | |||
| 13c8149046 | |||
| 665db0f778 | |||
| 173286de65 | |||
| f2ecda8fec | |||
| 6f1222e9bf | |||
| 84a424f21e | |||
| 9b7710488b | |||
| 9f413862e9 | |||
| b8802d7df7 | |||
| b13dad02a4 | |||
| f045f8d805 | |||
| 30b7c8ad66 | |||
| 89222a0ab2 | |||
| 21e637d2b3 | |||
| 6c196931d2 | |||
| d7195b0798 | |||
| b40998de9e | |||
| 8c0c327df9 | |||
| 50cbb8a1fc | |||
| ff9d058392 | |||
| 1acc8f438b | |||
| c53426fcb4 | |||
| 5187db525f | |||
| a8bd340267 | |||
| ca1f419dc2 | |||
| fae60a6b88 | |||
| 108558ddfc | |||
| 65b8cfae82 | |||
| 4055c31cf0 | |||
| e88af4e458 | |||
| 79eb7b52d9 | |||
| 83b2bf44c4 | |||
| 670f18ad1b | |||
| 9a81716936 | |||
| f013499eea | |||
| d04f732e68 | |||
| 35fd8e7f68 | |||
| 38ff2a3ed9 | |||
| bd502d16bc | |||
| a11e17fbc3 | |||
| 8b3b659433 | |||
| f33228fd6e | |||
| df5b693de8 | |||
| ab98108441 | |||
| 6f80174f84 | |||
| 0ebe81fce2 | |||
| c75dd14308 | |||
| c166b6a21d | |||
| 6ed5cbee12 | |||
| 5b200ccdf8 | |||
| cf0f0c4b31 | |||
| 1399ecb41c | |||
| 339d6cfd41 | |||
| 7bded4f189 | |||
| c7269b9ef0 | |||
| 85688015aa | |||
| 3c6cc575c6 | |||
| 0564cb6483 | |||
| 4be92c7eb8 | |||
| 88e9eb7d0c | |||
| d19fc54c3d | |||
| 5d4291d9fa | |||
| b70cd03e9e | |||
| e91e5e1fe9 | |||
| ae57a49915 | |||
| bfcb527b42 | |||
| a343fb171d | |||
| fa2296a124 | |||
| a996cfc536 | |||
| c1d55b9296 | |||
| 5c18cca1ca | |||
| 78e6cd0c60 | |||
| 176954a6d8 | |||
| ad6b3bd95f | |||
| 762895bc45 | |||
| 592e9afa5f | |||
| a2e0373934 | |||
| fb49841b1d | |||
| 01ea0d6f1e | |||
| bb7f291f5f | |||
| 174fa9b490 | |||
| dda2ed290a | |||
| ee9908b09e | |||
| 66de1856e3 | |||
| ba5f7c4e2a | |||
| 487bd3d942 | |||
| 4fac7a8f27 | |||
| 25dae06b6a | |||
| a1f15c2c69 | |||
| 516f6647b4 | |||
| a7840d50e2 | |||
| cb10af08cb | |||
| 4e49d24df9 | |||
| 68222cb8ab | |||
| 912d29af83 | |||
| f3868ac932 | |||
| 5b42dd7707 | |||
| 51707032d1 | |||
| a0babefe55 | |||
| f3aefbc443 | |||
| a6c779b50e | |||
| 9fa41a97b9 | |||
| cef022539e | |||
| f6dfa33697 | |||
| bc3bf939e0 | |||
| f5e5eac3b9 | |||
| d50786bd30 | |||
| 0ccbea17aa | |||
| 136d50a745 | |||
| babfba5e8f | |||
| 846f8377b2 | |||
| 77d4409549 | |||
| 7f3540b7f5 | |||
| 3ad2cde833 | |||
| 910799cc5f | |||
| 6c0192083e | |||
| c60d7842cd | |||
| d7eaf0f87b | |||
| bb4329711c | |||
| 618d3bf62f | |||
| cf8a4b9812 | |||
| 4db533ff71 | |||
| f28e3276e7 | |||
| 026540040d | |||
| 8518d3b232 | |||
| 1c1f5e2231 | |||
| bdedfb1071 | |||
| 92ed9e0b94 | |||
| 5c10b35df7 | |||
| 0668811397 | |||
| 6bb6344208 | |||
| 2f7bd154a2 | |||
| 20c5033b38 | |||
| 20fe6d102a | |||
| 4e30a64d9f | |||
| c48ef7d70b | |||
| e079a7009d | |||
| f383bf3136 | |||
| 609ddf28b7 | |||
| 34f1bda57c | |||
| f137b927b6 | |||
| 2185dada56 | |||
| 0b08080119 | |||
| 432b2b19e9 | |||
| 952f294bce | |||
| c23274adb0 | |||
| 833f9dd037 | |||
| 1ff8b97dae | |||
| 70451f9335 | |||
| 1f438d4e6c | |||
| 421d45a7a7 | |||
| 20e7b5c88a | |||
| 7092273a8f | |||
| d0e8a735ba | |||
| 208226dba2 | |||
| f308f37ba1 | |||
| c2610cb75e | |||
| 59e9df2609 | |||
| 66b5a35ec3 | |||
| f3f6c12a7c | |||
| e331b0647e | |||
| 35502816c7 | |||
| 7ec0236fbf | |||
| 0fd43c1a0b | |||
| 06337129d8 | |||
| 337780497d | |||
| 10deb2e88b | |||
| b95ca80f85 | |||
| 83d880a94a | |||
| cde6a2f7a5 | |||
| c2f5cbdeb4 | |||
| 8e57511ffa | |||
| 12d19d21c4 | |||
| 7002c94a63 | |||
| 57e69ea392 | |||
| 09f936b04d | |||
| 140c00aa0c | |||
| 808ea30b48 | |||
| 63d6c08d90 | |||
| 10e4de3c01 | |||
| 8ac12886ed | |||
| 63cc8a80a0 | |||
| 1549d01bf7 | |||
| b168bf9460 | |||
| 0203bb657e | |||
| 53f0c6ef1a | |||
| 4c4480104d | |||
| 5c72974167 | |||
| f21e9ee712 | |||
| 81dd727f75 | |||
| 3b54015e80 | |||
| b032d5af87 | |||
| 209a155608 | |||
| d8e77cd738 | |||
| 95d4ce4aa3 | |||
| 39393cca92 | |||
| acadbe050c | |||
| 8fcf2f5dca | |||
| 831a86599e | |||
| 233b32fd3e | |||
| 3c5124ce68 | |||
| a8d78660ee | |||
| cc1df9591f | |||
| 54a326f046 | |||
| 3d9d85121d | |||
| a31d23a32a | |||
| 084f431aa5 | |||
| 7002f0a7d7 | |||
| 3ec70c5517 | |||
| d9f293b281 | |||
| 8c1499dbc2 | |||
| 7d2eedee73 | |||
| eba35a8f7d | |||
| e967f2ca2c | |||
| 438713af20 | |||
| 568869077e | |||
| f25a3f2a7d | |||
| 5609221831 | |||
| f3432e6bb5 | |||
| 43b350c590 | |||
| c2c66aad60 | |||
| d7681d5b06 | |||
| c902615192 | |||
| 2895830ce6 | |||
| 1eef9552b4 | |||
| 577fa2d29b | |||
| 72fcf16a39 | |||
| b9d523e0b2 | |||
| f3d225ca4f | |||
| d84d2f85e8 | |||
| 10f1d8c604 | |||
| 184d1c57b1 | |||
| dfbe68bcfe | |||
| 3049e07f72 | |||
| da54d0ec8c | |||
| b57edb89eb | |||
| e43eccbb91 | |||
| e48f41165c | |||
| 9eb4cbcbd2 | |||
| 2612f241c9 | |||
| 0f1153fae2 | |||
| b84561f2b8 | |||
| f7e78e2671 | |||
| d10a2bc5d5 | |||
| 94fda3d48d | |||
| 5cf4f565d6 | |||
| c20b5cbd10 | |||
| 115612620f | |||
| a5bf3b0bc5 | |||
| 5c647e2f61 | |||
| 06884da42b | |||
| 6e7179d8f3 | |||
| e85f1dd9fb | |||
| 9ac94e621b | |||
| db8d119cad | |||
| 836c325021 | |||
| 3bb31093fa | |||
| 214b43974d | |||
| 55556aea77 | |||
| 223897d224 | |||
| 542e45de26 | |||
| 1fa9488a4d | |||
| b1196bd659 | |||
| 57167be2a6 | |||
| 846930a07f | |||
| 0cc67ff5e3 | |||
| a86574da84 | |||
| 5a6836ab99 | |||
| 43432f92ec | |||
| d1499f3f78 | |||
| fff23e2bbb | |||
| 33895b6d92 | |||
| e10105a780 | |||
| 5451c9672d | |||
| 4eba2bb8d9 | |||
| 2a58bceb56 | |||
| fdcf08410c | |||
| 5142955f00 | |||
| 500150b12a | |||
| 50ddd8dd26 | |||
| 6c6de2a07d | |||
| 01912b6ba5 | |||
| be2c7b5c9b | |||
| ed60ed3bae | |||
| 23cb96de02 | |||
| a2c771876e | |||
| b5b329378f | |||
| f7b18cd86e | |||
| d74e4b427d | |||
| 22dc020647 | |||
| e8485ee7e7 | |||
| c516fb947f | |||
| 3aa0a733f3 | |||
| 4e080057fb | |||
| 9c1f270bd5 | |||
| e46d87b221 | |||
| 5bc866e420 | |||
| 5af7004f44 | |||
| 01e8e682c0 | |||
| 2ef6544ca2 | |||
| 9921ac01cc | |||
| 7057f5fc11 | |||
| f17a9dd5e7 | |||
| ec3394b8da | |||
| 0cca42a1f4 | |||
| 85edcf9cc2 | |||
| 3b842ffe29 | |||
| 6c0e2e2a53 | |||
| 42371f7aea | |||
| 286f782e5e | |||
| 58fc305b11 | |||
| 7e0c359f99 | |||
| f50399e394 | |||
| 7bc21c6691 | |||
| dd56c85e55 | |||
| 9e2a847ebc | |||
| daef39a206 | |||
| 5d496cdcda | |||
| f27f595549 | |||
| 536e0a8c29 | |||
| bc18310107 | |||
| 3fdb3dd767 | |||
| d224679619 | |||
| 2dd181e663 | |||
| f002857edc | |||
| 97739da85a | |||
| 6c14586fff | |||
| 0c45a46aab | |||
| d1fc9d3073 | |||
| 2fb351bf04 | |||
| dc832ad49f | |||
| eef44b11f3 | |||
| bb4f108487 | |||
| ccb38c3dc6 | |||
| cc81057d21 | |||
| 8b4b81fdeb | |||
| 4cb46f5631 | |||
| f4ad4c7aa6 | |||
| 37dda30c49 | |||
| 8fb718245a | |||
| a4cb6f96ea | |||
| 56e3b7cb7d | |||
| ae1f5d2181 | |||
| b4df272eb5 | |||
| dca2fbccff | |||
| d48d3bfa87 | |||
| 8559790bd8 | |||
| 37c6279031 | |||
| 0d4e710b96 | |||
| 205aa10b88 | |||
| 6f1cc3946b | |||
| 253ecd55a0 | |||
| c9e31dc90d | |||
| 3d06322d4a | |||
| 85e6efdf16 | |||
| 6b89ff43ea | |||
| 4cdc55af91 | |||
| 4b289f904c | |||
| 53c70da0b8 | |||
| 6f20b5bb59 | |||
| 96ab17ecfc | |||
| 18bde22b26 | |||
| e61aad925b | |||
| 5d190b15d7 | |||
| fe442d7c0c | |||
| 97d1a67871 | |||
| bac96cf2ad | |||
| 7e0cc0af25 | |||
| 1d29d9be25 | |||
| 0e91e63043 | |||
| 0cf37bde8b | |||
| 173799527a | |||
| 5931e2383b | |||
| e4743b15b1 | |||
| 9f95d6fa65 | |||
| 982a1aebb3 | |||
| cec049b7d3 | |||
| dc323cfa1d | |||
| 0afa226a93 | |||
| 1146604344 | |||
| 89c2e1a5fa | |||
| 971d498e79 | |||
| 6e7a50c02f | |||
| 6aaab4988e | |||
| d9b0c05acf | |||
| 47f637d23b | |||
| 59f55a2119 | |||
| 8bac82320f | |||
| 14bf20320a | |||
| b99940f33a | |||
| 81495068b9 | |||
| 6985181961 | |||
| 97717d65ef | |||
| 8023c8abc7 | |||
| 2d3f59d9a7 | |||
| be8de4a1ff | |||
| 18ad6c33ef | |||
| 0e27b27b81 | |||
| 10a311092b | |||
| 18463d68d4 | |||
| 74d3bcec05 | |||
| df233aee94 | |||
| 335b724209 | |||
| b2fdb881eb | |||
| 6ade9acc4d | |||
| 2081f8fcd6 | |||
| 964ab4814c | |||
| 7a032cf9f9 | |||
| 694c13fe86 | |||
| 8bd16c32f3 | |||
| be9b935953 | |||
| 9e69452327 | |||
| 234d529867 | |||
| dd8b71e353 | |||
| d24bebdb9e | |||
| 41a18f078d | |||
| 3978e7e1ca | |||
| b758c696f2 | |||
| d6a8216ce4 | |||
| 2720f64c06 | |||
| de2ebdd5cc | |||
| 4e39629a9a | |||
| 78a8da5fea | |||
| d5886c1572 | |||
| 7cc759a855 | |||
| dd6337224f | |||
| d2bac0c35e | |||
| 8c7f3fd1e6 | |||
| ae3deea153 | |||
| 40bea95fb0 | |||
| 0ad448f1c7 | |||
| 4911df9f99 | |||
| a223340c44 | |||
| 9c9c2b483c | |||
| 819345caa6 | |||
| 11ceb3973d | |||
| 36263399a0 | |||
| ff0f0c447f | |||
| aa681932a9 | |||
| 09e1c0fa27 | |||
| 957ef8e8fe | |||
| 2e11a8da5b | |||
| e9cfcf9ecc | |||
| 789ab99c4d | |||
| 0297db6f2e | |||
| 9ce64916e6 | |||
| 1289c96e2c | |||
| ba23bfb7b9 | |||
| 2fae6eda23 | |||
| e53ba3b116 | |||
| 1ed84a064b | |||
| 79019c7a09 | |||
| a1002e6960 | |||
| 62139cb5a4 | |||
| 127b0ba65e | |||
| 80878264b6 | |||
| 9fcba99ca2 | |||
| 03c9212600 | |||
| 5650087aa3 | |||
| 67689ecb21 | |||
| cd13dedb36 | |||
| 10cd294cf2 | |||
| d6cfb60506 | |||
| df0df73540 | |||
| 33f1418dec | |||
| 305510bea0 | |||
| beb698f31d | |||
| 6df21d6a9f | |||
| c5982e52d5 | |||
| bd73b2845b | |||
| da0f722aad | |||
| 904f0407f8 | |||
| fbbb0d7610 | |||
| 3a9b0a22e7 | |||
| c4e0d1efa1 | |||
| 9349dfba8f | |||
| 9692496989 | |||
| 5bc8164274 | |||
| a6cef2e50e | |||
| d262eda91c | |||
| 40f0f5ad8d | |||
| 1c03e68057 | |||
| f1c1cfb6d2 | |||
| ba5e33bc35 | |||
| 80df9fbc65 | |||
| b68ab0dd6d | |||
| 9cf7a31068 | |||
| 5e11ad2e1e | |||
| 07d1a42768 | |||
| ec8221cb5d | |||
| a5342a0126 | |||
| c81fd2e5dd | |||
| 3bd7122959 | |||
| 530401e5ee | |||
| a412d34574 | |||
| ee67a0b9a1 | |||
| ca6a1db757 | |||
| 1fb76ad768 | |||
| e01662c139 | |||
| 63331ef731 | |||
| a40a53b104 | |||
| 9f8d90f466 | |||
| 3d2856db31 | |||
| f4723aea4c | |||
| 76d48b38d3 | |||
| 3cab2592c3 | |||
| 5422a3b17e | |||
| b44b6e7e50 | |||
| 849efff070 | |||
| b022167df1 | |||
| ac9a358c65 | |||
| e799476f90 | |||
| b4f8efcbe6 | |||
| f026753692 | |||
| 71b1cce517 | |||
| d8f0da164b | |||
| 591732f347 | |||
| eee97f7f62 | |||
| 3dd9da1b66 | |||
| e8c0be23f2 | |||
| a30b9b17b3 | |||
| 29b2c04766 | |||
| d869ba7bcd | |||
| 581255bf23 | |||
| b51358a01c | |||
| 323e7a2d02 | |||
| 7654afc2db | |||
| ded8342f3f | |||
| 240fb9b953 | |||
| 4997a43763 | |||
| aa4eb35671 | |||
| d99ba9c073 | |||
| fdd24f787f | |||
| b6abd691f4 | |||
| 8d370fabdd | |||
| df4a0c62ad | |||
| e3e3309a9b | |||
| 7428e52264 | |||
| 20b70c3b7b | |||
| 4247ba67ed | |||
| e738e93da0 | |||
| b78f3a8069 | |||
| 939973acd7 | |||
| ed4cb72b19 | |||
| 70cbffd58b | |||
| 6d0ba8d189 | |||
| b6f3fa6ee1 | |||
| 91037766d2 | |||
| 8bf73950fa | |||
| 4f4793817c | |||
| 0a0440a6e8 | |||
| b9dc81d808 | |||
| 8e7ddccf00 | |||
| a5773f1657 | |||
| 44316401c9 | |||
| b05fbaacda | |||
| 1b4d5b73ab | |||
| d3fbf36df7 | |||
| de819cff94 | |||
| cfae39c29d | |||
| 989641a616 | |||
| fc3f62e3ed | |||
| 6b7c04e046 | |||
| cfeb16f917 | |||
| 9a2d9002e6 | |||
| ea0b02d9b9 | |||
| 0d621511e5 | |||
| e53c858855 | |||
| 8a9f7fc684 | |||
| 51db46551e | |||
| 600b79276a | |||
| a040be957f | |||
| f6fa553572 | |||
| 8310436350 | |||
| f92ffe60e7 | |||
| de72754d7a | |||
| bf712e9355 | |||
| ab9457346d | |||
| 15b440c4f1 | |||
| 1a2c36e482 | |||
| 56737c1431 | |||
| 9ae566adcc | |||
| f2f1330238 | |||
| c4a7739d13 | |||
| 8a8b5c753f | |||
| ad90f416a5 | |||
| 698fcb7813 | |||
| aadb4db211 | |||
| 426a6a9528 | |||
| 50b9c48609 | |||
| 767ed21bfe | |||
| bb9165edd2 | |||
| ad0a413b40 | |||
| 7f6c6945ae | |||
| ca549939f3 | |||
| cdb003bf23 | |||
| a4d2ff05a9 | |||
| 48012ec73c | |||
| e7dc00b758 | |||
| ef1fbbbce6 | |||
| 2a59aebe5b | |||
| 59025b75ba | |||
| 2289b7a33d | |||
| 79ec172797 | |||
| 2e6ad2a711 | |||
| 6be05f315d | |||
| b5aa50aaa4 | |||
| ab91fa6ad5 | |||
| 376327c87b | |||
| f8f91e52e0 | |||
| f4daf46ff4 | |||
| e80bee6867 | |||
| d10d54710c | |||
| 1ec997461d | |||
| ec5fc10988 | |||
| a232c0888c | |||
| cb5a6b531a | |||
| c930a3b4c8 | |||
| 4c14e92952 | |||
| 850d4a1e1b | |||
| 88de3a1c06 | |||
| dc012ed6dd | |||
| c21c993646 | |||
| c3a292a8c7 | |||
| 4044a577cc | |||
| 581d53b96b | |||
| 2bc89260f1 | |||
| c78b83f142 | |||
| e28525e28c | |||
| 73f9d12d47 | |||
| b21cf05d44 | |||
| 107bede9fd | |||
| 75cbb09744 | |||
| 76cf667a29 | |||
| 78ee97ec74 | |||
| c686133172 | |||
| bfcd7a35bf | |||
| 4484a3433d | |||
| 0c4f905d82 | |||
| 77de7ebde5 | |||
| 2ec3fa93b4 | |||
| 9f2d710c35 | |||
| 22b961ea53 | |||
| 9ea45d35db | |||
| 06e8476efc | |||
| 94dbac9a64 | |||
| 97a183f412 | |||
| b2f5b73532 | |||
| 1eac3482a6 | |||
| 6636376a81 | |||
| ed6bf28004 | |||
| 6bc0c611ab | |||
| ba1930eb01 | |||
| 203382461b | |||
| 6456618891 | |||
| 4eb4ae6305 | |||
| 72ae061769 | |||
| 46161f7e19 | |||
| 0c55596f0f | |||
| 5f3bfa66c5 | |||
| 561b725b0e | |||
| 3a4630e6b4 | |||
| abf0fd7efc | |||
| a632db3618 | |||
| a3c81374be | |||
| 6a3ec5eb36 | |||
| 740ba6ad47 | |||
| df32b5b46c | |||
| 085fa199ea | |||
| 412c9a99d5 | |||
| 6e701ef36d | |||
| 24c48d22bc | |||
| 3cb8bb6672 | |||
| b1c2c0ea7a | |||
| 2c498c132e | |||
| 880d330cca | |||
| a2a503847a | |||
| 58f4d533b7 | |||
| d2ff6f424d | |||
| 92f985abd5 | |||
| 3ce17607c6 | |||
| 76277f83c1 | |||
| 2b7529977e | |||
| f4125d2d88 | |||
| 87e50e5e4d | |||
| 86a1c34c3a | |||
| 3f3cc342b4 | |||
| 3bf820cf99 | |||
| f2b4087d80 | |||
| 3b6d72bb94 | |||
| 9080fa4a9d | |||
| 5616ff9a40 | |||
| 73b81184fa | |||
| f8d3f86d8b | |||
| 2f9a410a45 | |||
| 8661457512 | |||
| 5d7b92d391 | |||
| 1d8bc3e917 | |||
| a2ad16b609 | |||
| a3b1ac3133 | |||
| e7b96cf286 | |||
| 01181517dc | |||
| f702c782f1 | |||
| 7203560b06 | |||
| 1baeb9406f | |||
| 17e36bd5e1 | |||
| b6b3377786 | |||
| 13cb894b30 | |||
| 3f935bea25 | |||
| 3e66eec735 | |||
| 277e0ac124 | |||
| 2ccfaa7d4e | |||
| 4bd5de34ea | |||
| 374e71e9b0 | |||
| 07bb93bb5d | |||
| e252d3bedf | |||
| b9efd09d17 | |||
| 507b718cb3 | |||
| 82f9cbecf8 | |||
| a8ac59a6e7 | |||
| 3d389ee028 | |||
| 10c5825715 | |||
| f89ebce807 | |||
| 64601ac439 | |||
| edce27812f | |||
| 193822b45d | |||
| 43640a8b59 | |||
| 0446d9721b | |||
| bae13b6387 | |||
| e48c0eee74 | |||
| 47e9857eb7 | |||
| 559fcfa291 | |||
| 84cee5d9d5 | |||
| 6d354524e2 | |||
| ae6441182d | |||
| a68f0b2d72 | |||
| fdbbf24271 | |||
| df233f72a9 | |||
| bff5a67f79 | |||
| 4f9df50dc1 | |||
| 34187424b8 | |||
| 50503cb405 | |||
| 5e04ddd653 | |||
| 4f5203e661 | |||
| d9ca4eb4d6 | |||
| 5534c031b3 | |||
| 19dc84e300 | |||
| a932168f50 | |||
| 36c22393a4 | |||
| 6d6e840bc2 | |||
| 4b1822ade8 | |||
| b21e7e4518 | |||
| 1f4e5e919f | |||
| c293e88f2e | |||
| 1d147ba993 | |||
| 6ea9ba16e7 | |||
| 286549693e | |||
| 34727f99e3 | |||
| ffe6d81ecd | |||
| 8605833781 | |||
| 4474144c24 | |||
| ef3f448861 | |||
| a882260db6 | |||
| 633157f4f8 | |||
| 9fa69c3d3b | |||
| 743a461aa9 | |||
| fc0291d745 | |||
| 77eaf8e1e4 | |||
| a7adb2fb6e | |||
| 036900da51 | |||
| ed4c9335db | |||
| ca67cf032c | |||
| f907516cbd | |||
| c12c7d5370 | |||
| f7c8b40ea2 | |||
| 15f9795ab0 | |||
| 8982ae34e3 | |||
| e6d3e893a5 | |||
| e008b5a160 | |||
| 3da8fa9b27 | |||
| 32ba5e7ad2 | |||
| 52df80dccd | |||
| 7f845bb165 | |||
| 0e6de5673b | |||
| 7a7b87181d | |||
| c6dc517004 | |||
| 0b61215f7b | |||
| b91c0ec715 | |||
| bad295cf69 | |||
| d2bc41a2df | |||
| 7dbcaf792d | |||
| 2652c2d7a5 | |||
| a2250a5d49 | |||
| 7f8a9587e0 | |||
| 1306c53fb1 | |||
| 3bd1ac4c82 | |||
| dc8d28c383 | |||
| 7adaa4dc2b | |||
| 6d1a91f5b3 | |||
| 17eebf338c | |||
| c543ecd64c | |||
| 34a9f55f37 | |||
| 9aea990184 | |||
| d5b0632e4f | |||
| db169a4334 | |||
| f5cc8bd7bf | |||
| 005d52cab7 | |||
| d1477bcfa7 | |||
| 3092fb2ff3 | |||
| 5eebdebec8 | |||
| 8e4d6b3e5d | |||
| ea9c2fed57 | |||
| ba412fd87b | |||
| 0278ac85a0 | |||
| ff60b752bd | |||
| 832003dd4b | |||
| 9848e883c7 | |||
| 64705ddd1d | |||
| 2a41814985 | |||
| 26ffec845b | |||
| 52e60526ef | |||
| 76b10b5f5d | |||
| b94a7a87fa | |||
| 2b43387a9d | |||
| e76a5d8e12 | |||
| 6d7217f37a | |||
| 17dab04422 | |||
| 29e660b16f | |||
| 31959b0751 | |||
| 1f19610fd6 | |||
| 8f897de267 | |||
| 2855ff6df3 | |||
| deed20dea6 | |||
| a6c5143993 | |||
| 758d1e2a03 | |||
| ce057ff755 | |||
| ad719e7c3a | |||
| bff3426d25 | |||
| 4315033220 | |||
| 1cd89b2da3 | |||
| 658a605c75 | |||
| 7e8b9862b9 | |||
| 07062324d7 | |||
| 2e8f2e6dbc | |||
| 1abd95094d | |||
| 913d802e33 | |||
| bee475c38a | |||
| b4ca99ead9 | |||
| dfe2c0a600 | |||
| fad851d80c | |||
| 832961d539 | |||
| 499c657ffa | |||
| e51bb4ef12 | |||
| 8c6f39a68d | |||
| 09f5713cf8 | |||
| 26c0c6a525 | |||
| 6d9f84ba03 | |||
| 8af08f2153 | |||
| 2944969ca0 | |||
| bd1b54e0db | |||
| fcab5508be | |||
| 0b05650366 | |||
| 96e36c7c39 | |||
| 16c6dbcbe5 | |||
| 92a78c83d9 | |||
| 6b2302fa8b | |||
| ee28945e09 | |||
| 3dcea60f5b | |||
| f126e05034 | |||
| 68b74eb7c7 | |||
| 3b4199a669 | |||
| 562901aedf | |||
| 793117ed63 | |||
| 5b783d6376 | |||
| d3f3528d1d | |||
| 3145935d6b | |||
| 25430333ba | |||
| 2ca2b32dd0 | |||
| a5dde78f08 | |||
| fd415f0b45 | |||
| 507722954c | |||
| 524d23d45d | |||
| e9ee6f5291 | |||
| 7e5342f41f | |||
| 18607e53cb | |||
| ed933b3f21 | |||
| 49fecbdc5e | |||
| f971126183 | |||
| d4ccb69ccc | |||
| 37b4e0de6c | |||
| 737f440c7f | |||
| cba3f1e374 | |||
| a70dde34da | |||
| 410b85b5c7 | |||
| 0ae012ba08 | |||
| fc4eb4152c | |||
| 4f3b5d8dcb | |||
| f76f70c7cf | |||
| 15d783e920 | |||
| 09e4fff5b1 | |||
| 2d89faa17c | |||
| dd9843aa21 | |||
| 882116e358 | |||
| f3adbae1ed | |||
| 278e239973 | |||
| fda803b46a | |||
| 01162e08b5 | |||
| a7ae197a55 | |||
| 3c72cb67d3 | |||
| 37bba4c0a6 | |||
| ab9d1f99fd | |||
| 45124e4d5c | |||
| 7681c43b14 | |||
| 7e43cd7d97 | |||
| c223fc1766 | |||
| 04297bb680 | |||
| 553292ffd0 | |||
| 57862846a2 | |||
| 8e270d3a99 | |||
| ae5cb09041 | |||
| 093b2288c3 | |||
| ffe17a471d | |||
| e9f901b82d | |||
| ed3004f8a0 | |||
| d97df080f9 | |||
| 0e5c7e08fc | |||
| 83523badb7 | |||
| 0a90994403 | |||
| 376906e0ae | |||
| 47c79a2f25 | |||
| 32988b0363 | |||
| 00c138ce9f | |||
| 5676c9e7eb | |||
| 3a469dc13e | |||
| d3c70f2206 | |||
| 14f1793b3e | |||
| 8cecb6b9f5 | |||
| 4a66c3c420 | |||
| c3c88633a5 | |||
| aeaf1199ec | |||
| d4f62f52db | |||
| 384fb76a1b | |||
| 4a04a32e0a | |||
| 196bd735d4 | |||
| 493bc653b5 | |||
| 3d209798c9 | |||
| dd0d61e97c | |||
| 4b9324ff76 | |||
| e81ed9a960 | |||
| 83f7a887b7 | |||
| ad2f1ac24e | |||
| 62d232d798 | |||
| 8906a0120c | |||
| cad753e398 | |||
| fd627dc13b | |||
| 70e8d97ee1 | |||
| cdecb0ccc3 | |||
| 460b5149af | |||
| b6dc253d8b | |||
| e7be9493ba | |||
| ea34f321ed | |||
| 2b5bc1d558 | |||
| e6a7b85da4 | |||
| 6145185478 | |||
| 6630d703f8 | |||
| 9c3cdc4620 | |||
| 345032f804 | |||
| 2abba6e057 | |||
| db5a1b0c78 | |||
| 14cb19c2df | |||
| 46bcd18946 | |||
| 3e5c60f746 | |||
| 0fa487f468 | |||
| 1bec9e5331 | |||
| ba61d911da | |||
| 3b69c6b204 | |||
| d7eabf571c | |||
| ddf9c4a65b | |||
| b3d797598e | |||
| 31c7945444 | |||
| 276e014d18 | |||
| 27f206784c | |||
| 54a6637d38 | |||
| 23be56af59 | |||
| 71df46456a | |||
| cd89d8a3c4 | |||
| 4c62a32b04 | |||
| 5f8137025d | |||
| 1843d52217 | |||
| 454c92dc64 | |||
| 7e33a86d54 | |||
| 197b832992 | |||
| 8f13724a4b | |||
| 746d5fc322 | |||
| ffc45e8cc2 | |||
| bea2f36443 | |||
| f138f71fa6 | |||
| 89b7a3f7ac | |||
| 75e15b05b0 | |||
| 78eb388110 | |||
| df23cf47c6 | |||
| 002ac6a1b7 | |||
| 40e4536887 | |||
| 536bf61323 | |||
| c76bdced55 | |||
| 459ea5f4f6 | |||
| 8e8a075a22 | |||
| db6bd9b358 | |||
| 42ad54c28e | |||
| 1857bc7b02 | |||
| e011d812ca | |||
| 0738822dda | |||
| 2213722776 | |||
| 65dedbb1ca | |||
| 0e69993d39 | |||
| 135091ddbe | |||
| d64e3b672c | |||
| a3bcacee27 | |||
| 855e7beab1 | |||
| edc13c29df | |||
| 21864d8d51 | |||
| d45ff0694d | |||
| d695a8a526 | |||
| 0380a288a9 | |||
| 1d4d0a3e1a | |||
| 9e98494fff | |||
| 86d334282c | |||
| 9cf937fef0 | |||
| f5697dd7f2 | |||
| a23ee1edc1 | |||
| 9dcb5c075a | |||
| 803648be89 | |||
| 3ab5db8297 | |||
| 3380ece4a1 | |||
| 0e5928ff39 | |||
| e6e04fc6c8 | |||
| 753cceea82 | |||
| 32c7e81745 | |||
| 03aec70287 | |||
| e69738c079 | |||
| 1afa7967f2 | |||
| 643e36b87b | |||
| 3d2405ac2c | |||
| 7392a3047a | |||
| 60f4d8f1ec | |||
| 7b42cbea20 | |||
| 4cc597f4df | |||
| 934e66ab3b | |||
| b755609438 | |||
| 83d63e572a | |||
| 5212f62f54 | |||
| 4d0fd4cf19 | |||
| e47953f7ca | |||
| 47f3773146 | |||
| 31c6ecad34 | |||
| af6e53c05c | |||
| 153140eb8f | |||
| 6fef44c041 | |||
| a88d149903 | |||
| f9fc488399 | |||
| bef806bef4 | |||
| 95e9bbf99f | |||
| 5936fa8871 | |||
| 02646b789c | |||
| 09e9dca869 | |||
| 9a43c0672e | |||
| 83a6169463 | |||
| debe2de5fe | |||
| ff7d591ebf | |||
| 7386ca9272 | |||
| fd8b2e0b88 | |||
| c34ae884ad | |||
| 2e7157ae9c | |||
| 441365b388 | |||
| f561147190 | |||
| 2958c1d6aa | |||
| 9dc83bc1b3 | |||
| 88b1b2c629 | |||
| 23bc643a81 | |||
| 41854bacf5 | |||
| cf528431f5 | |||
| e59064dd59 | |||
| 8966294823 | |||
| b8479ea79d | |||
| e2aa8f426d | |||
| 39a0f8c96a | |||
| b647b45ba5 | |||
| 5fe9aa919b | |||
| ff5d6a994b | |||
| ae3b95b194 | |||
| acaae1357c | |||
| f8afda3b22 | |||
| 31f544c258 | |||
| 1c57d1c019 | |||
| 251edf7bc7 | |||
| f77cd5533d | |||
| 416413bebf | |||
| c3809d7b84 | |||
| 42a1c58a80 | |||
| b6abaf739c | |||
| ef98e92e8d | |||
| 768c2684d0 | |||
| 5f2514db63 | |||
| b95ade40c0 | |||
| 340838c878 | |||
| c5d348515d | |||
| 05dd3d490d | |||
| 0cc40db565 | |||
| 546faab0cb | |||
| 83e9a6b417 | |||
| 30bb2382aa | |||
| 61a0b4ec5a | |||
| accb35506f | |||
| 817bc7434d | |||
| 3c2ed3bb69 | |||
| 9cbf46e689 | |||
| ad6ea3d6aa | |||
| cda9fd5271 | |||
| 0c16f27814 | |||
| 19aec13a10 | |||
| e896956275 | |||
| c59c6e98a5 | |||
| 8b1100bf2b | |||
| a3d99765cc | |||
| a724573bb3 | |||
| 25769f139a | |||
| 3edf638cc6 | |||
| de7e612186 | |||
| a571153458 | |||
| ada58c66fa | |||
| 697f8c7ee6 | |||
| b6ebfe4b2c | |||
| bccbdefde9 | |||
| 445ca70521 | |||
| c6ab8f82c8 | |||
| 67ce0ec29f | |||
| 23c3573c30 | |||
| a4308e7246 | |||
| 3439139b1c | |||
| cf246f65ff | |||
| dd84b61cc8 | |||
| b8c4bf2afb | |||
| e870041fe6 | |||
| 6418ec3b21 | |||
| 2bcc7b0064 | |||
| 97be867103 | |||
| fb710f8cbf | |||
| 1553137c23 | |||
| d5384c5aa4 | |||
| 3a81f2ab89 | |||
| b54fc96b1e | |||
| 48af78e469 | |||
| a315e7c962 | |||
| 42364f2fce | |||
| 8f600798ef | |||
| abb26e0bea | |||
| 76edfae0e0 | |||
| a5298e17ec | |||
| cf9f3d5e2d | |||
| 35c90fe124 | |||
| df8bdac33f | |||
| b4f7a527c2 | |||
| 35533a7baa | |||
| 2c9ed7464f | |||
| e190c024fd | |||
| e250475bf9 | |||
| 5db603ded2 | |||
| 78815778ee | |||
| a04d849e30 | |||
| 8c9505505a | |||
| eac74631ec | |||
| 85706d559d | |||
| 67ba05cb7c | |||
| 2f1aeaf757 | |||
| 14a17fb36f | |||
| 1a9ec776cb | |||
| da1edac56d | |||
| 44ec95a983 | |||
| 1502066303 | |||
| 35a826a0fd | |||
| ebb8ca7c26 | |||
| 763de44853 | |||
| 62cc752066 | |||
| 965b962b29 | |||
| 2f3c5336d9 | |||
| 3824937295 | |||
| fc8ddcef5c | |||
| 3165b7cf95 | |||
| 5eea23cf76 | |||
| 2aa783179e | |||
| 24e7356825 | |||
| 2fcba25e50 | |||
| 28bc274449 | |||
| ff5e036773 | |||
| 4dc29d141f | |||
| 8ecee32e1c | |||
| 16786aac78 | |||
| 32b37f3429 | |||
| 5808793cae | |||
| 7e11f3cc4b | |||
| 714ab516c5 | |||
| 498f68c06b | |||
| 070b450768 | |||
| 74174eb4ae | |||
| b190404b21 | |||
| 081a5a52a6 | |||
| fb86c23dbd | |||
| cb6a4ebf60 | |||
| 1bf8328606 | |||
| 6a7f39453b | |||
| 515fd2a228 | |||
| dd3322ac1f | |||
| f16f1d932e | |||
| a3e7b2baa1 | |||
| fadf9b5309 | |||
| f6a087775e | |||
| d5f7e181a0 | |||
| 65f8722afc | |||
| c0479f1564 | |||
| fe0b5bf4e2 | |||
| f20105ddfe | |||
| 6a7d821fcc | |||
| 42ab882db4 | |||
| f28c268d97 | |||
| f1cff20249 | |||
| dcc9e61362 | |||
| 2554c72bb2 | |||
| 49872e40dc | |||
| 849fe01e70 | |||
| 1243b1a58c | |||
| ab3bae5c02 | |||
| 540c5400a0 | |||
| d269dbcd40 | |||
| 18e639f59b | |||
| 6ad262c2df | |||
| 10b97a1b39 | |||
| 56b4e0a3c3 | |||
| 27dbe84f79 | |||
| 0711d4e5fe | |||
| 1e46537959 | |||
| a5e1693774 | |||
| 01e29bf27e | |||
| 63771bc6e8 | |||
| 8516e2e7e3 | |||
| b3c3e41706 | |||
| 59f3a009fa | |||
| 9bc5b84c4d | |||
| f9265c14bf | |||
| 9c1e1a63a2 | |||
| 4dc5839e3d | |||
| fdcb9deaff | |||
| fe6539fad9 | |||
| 0e06383620 | |||
| 6223f48c3f | |||
| f2f20def37 | |||
| 77b91352ae | |||
| 3d7d347192 | |||
| e5868e3205 | |||
| cfbc1a447b | |||
| 1b23dd2257 | |||
| b612edba5a | |||
| d39c05b183 | |||
| 3a3cb521ab | |||
| 5b97ff0b48 | |||
| 2b918ada4b | |||
| b5754b6ed9 | |||
| 07ee23f817 | |||
| ecdaac9921 | |||
| 5ff82fc113 | |||
| 28a816ef25 | |||
| 6bdb210ad8 | |||
| db08847f9a | |||
| 841c428273 | |||
| 6b830f42b6 | |||
| fb01dfe048 | |||
| c7a9c8274f | |||
| cafb6e5587 | |||
| e9ae6e20e8 | |||
| 2ca2dbcc92 | |||
| 0d4642825f | |||
| 8eda756714 | |||
| c85ac955f7 | |||
| 97922406fe | |||
| 76ccce2942 | |||
| 686dbb4421 | |||
| cd6898439e | |||
| 96d7c4ffdf | |||
| 95620aaf2a | |||
| 1d293749c2 | |||
| 2d35a5c1af | |||
| d4ea02a877 | |||
| f19325cbe0 | |||
| 2a325b3da0 | |||
| d57ec4a11d | |||
| f0529535e0 | |||
| 3f59c45740 | |||
| 29ebe0c3c9 | |||
| 6c48670819 | |||
| 51dcbc80c3 | |||
| 9ecbadd457 | |||
| 79f32d7b71 | |||
| 7501cc2f17 | |||
| a390ef41f8 | |||
| bb9c2f7aad | |||
| 6aa80ee8e4 | |||
| 0741bc37cc | |||
| c6ed3fa4b5 | |||
| e277102947 | |||
| 6cf5371d7d | |||
| e15f714660 | |||
| 4f77151ebc | |||
| 9a46463078 | |||
| a0816bb581 | |||
| b33ca6651e | |||
| 315a08f33f | |||
| 50668fa7a6 | |||
| ee260986a9 | |||
| c9bc759624 | |||
| 80f175cdb0 | |||
| 8f03811842 | |||
| 3def94505e | |||
| e30f16b1f3 | |||
| 7df93ea504 | |||
| 6209b02bf9 | |||
| 75b7f2b9fe | |||
| f1521aa980 | |||
| fb0a3ab7c1 | |||
| 8eaafd5242 | |||
| 774951e8c0 | |||
| 5ec93677a0 | |||
| 7e4067c44c | |||
| f2f6c3c67d | |||
| 847b05013f | |||
| d308473075 | |||
| 4334dbe69a | |||
| 8f91e9307c | |||
| 32ec1162bf | |||
| 7cc265e14c | |||
| 6f3e450c50 | |||
| cb1080d56c | |||
| 80bd1eb615 | |||
| fb53402914 | |||
| 731853ce78 | |||
| f0260e9771 | |||
| af612bc7e9 | |||
| d76dd95c0b | |||
| 1cff72ad62 | |||
| 773cfac449 | |||
| b02f2953ac | |||
| 566a750899 | |||
| 1d1d684cbc | |||
| 7a14acaa01 | |||
| 057174497a | |||
| 8c9597b24b | |||
| 72862ce30d | |||
| d0f4cb1de4 | |||
| 17613185e7 | |||
| 00ff1fbca2 | |||
| f15bb0b424 | |||
| f818d0feb1 | |||
| 8ff6f95571 | |||
| 68e5f57e27 | |||
| 38e5e13b3f | |||
| defc1672c3 | |||
| 12f459b5fb | |||
| e6b8f7e77a | |||
| 236b08cb49 | |||
| e4f28de3de | |||
| 6543491148 | |||
| 3cbf9c3719 | |||
| 50188f0308 | |||
| a60b9735a2 | |||
| a032a2ef32 | |||
| f364ac60c2 | |||
| 43763ddfda | |||
| 70ed280c5a | |||
| 0d7cb02386 | |||
| bdf66bb1e1 | |||
| 9b5cfe2677 | |||
| 42033ea808 | |||
| c7ff296bef | |||
| 750ee4ecdb | |||
| ed742846cb | |||
| ed8b20da78 | |||
| c987b84292 | |||
| a9b17b5a37 | |||
| a66f859fb4 | |||
| c46e7eda1d | |||
| 865d88dd56 | |||
| 92e70b9a58 | |||
| 822da9d12d | |||
| b0817d136b | |||
| 53e30e4621 | |||
| dbf42d2469 | |||
| 36c61aeacf | |||
| 289b0422bd | |||
| 78359f0c16 | |||
| 3f8c6a6745 | |||
| 5d653a9d8e | |||
| 7f61a90ea1 | |||
| 982ec1e58b | |||
| 86f831ddd1 | |||
| 069c05669f | |||
| 516065d7c2 | |||
| 6f370fdbf2 | |||
| a60667e900 | |||
| 6889cb6fe2 | |||
| 9b2fe56d14 | |||
| 5d80e24224 | |||
| eec61c3f6f | |||
| dce120258f | |||
| 5752a374ab | |||
| 8dbeed8a9f | |||
| 84d774c7b4 | |||
| e2b36c4004 | |||
| 8453a6cbdb | |||
| 3e465c7e84 | |||
| 92ce7defb1 | |||
| a48317deee | |||
| ebdb3ab43a | |||
| 29ca6ee420 | |||
| 0548db4230 | |||
| aba6d2e52c | |||
| 4ebdb6740e | |||
| d0240b8981 | |||
| 4423bc0706 | |||
| 8c72813b85 | |||
| 08a081ed45 | |||
| b7c78da1fb | |||
| 3257454209 | |||
| 938744b276 | |||
| 84b84d9f7d | |||
| 85f8c8df91 | |||
| c889591333 | |||
| e2f53ee107 | |||
| c771ea9794 | |||
| 94bad4d786 | |||
| 1d7c9cf872 | |||
| 1e17d5d86f | |||
| 1e9b30666f | |||
| b2b79b86f0 | |||
| 3d85013aba | |||
| c94098c2ab | |||
| 9d4fe90356 | |||
| 6e61abc7d0 | |||
| a7138b22a5 | |||
| 7ec88d2430 | |||
| d7200f6144 | |||
| d65d6edb0e | |||
| 3d72e80ccf | |||
| 2dd67dba89 | |||
| 5807214406 | |||
| 23baf56c87 | |||
| beff90e1d1 | |||
| ec63d0bbd2 | |||
| 32eab04d66 | |||
| 682783a2aa | |||
| 46a4927aca | |||
| 9b2e67df67 | |||
| b5c828fe4e | |||
| 6ce5608003 | |||
| db42a2db47 | |||
| cecca96f3d | |||
| f1a126e162 | |||
| 9f0a30e36e | |||
| 517c8ff1dd | |||
| 2b07afaf70 | |||
| 6616882708 | |||
| c9c197ba08 | |||
| 7876660d8c | |||
| db9326f31d | |||
| 27106dd9ae | |||
| 33dc12a61a | |||
| ffd7ca57f1 | |||
| a4ba91a554 | |||
| 44897b5eac | |||
| 8255481204 | |||
| 1e453cf1d7 | |||
| c34a331696 | |||
| cf390bf8b9 | |||
| 07ec93bfeb | |||
| 994ee5a559 | |||
| 50057b0696 | |||
| 00597127dd | |||
| 70d4bc8573 | |||
| bc775afccb | |||
| 504ea7deeb | |||
| 5e2280a787 | |||
| 84e03421d3 | |||
| 0a87ffe0e6 | |||
| e5f961b48f | |||
| 5db505c42f | |||
| 275241f9b4 | |||
| 9246e89c4a | |||
| b56964e465 | |||
| 2e89585c8c | |||
| e230b7110c | |||
| a55f0cfb63 | |||
| de435c9318 | |||
| f40f12d480 | |||
| 8a2c829e07 | |||
| 42b9ce636f | |||
| ca6951d05e | |||
| 446f1f6183 | |||
| d424c84bf9 | |||
| 56d2bbc5b9 | |||
| 2c7bf87998 | |||
| daebaa8b50 | |||
| 9320a31f4d | |||
| 3e04b45106 | |||
| acd5878d66 | |||
| 4439d59105 | |||
| 12c1291805 | |||
| 61bc963e92 | |||
| ae59f214ee | |||
| 6bafa21bee | |||
| 61c581baeb | |||
| 6c4c9aef61 | |||
| 7bed317636 | |||
| 4647081f49 | |||
| 64db286582 | |||
| 1a7a6a9116 | |||
| d1e76ee4f2 | |||
| 9be0d18e5d | |||
| e877525073 | |||
| f09638318f | |||
| bb7703fcec | |||
| 1b28226a67 | |||
| 2b546a598c | |||
| b530ca9a5e | |||
| d232796149 | |||
| e721f26a76 | |||
| 91408cb21f | |||
| eb8b0d7a03 | |||
| 880af47ae7 | |||
| 91949b0992 | |||
| 6a101e69a2 | |||
| 1823b0cead | |||
| 1ec0b79345 | |||
| e814a3693f | |||
| f55fc4cd08 | |||
| f47311f2f6 | |||
| 3f038428a7 | |||
| b9701340b8 | |||
| 82110bf487 | |||
| a75dc9d86d | |||
| bfa23f1352 | |||
| c430a82721 | |||
| cc316a473e | |||
| c213274607 | |||
| c4a2580dfd | |||
| 8a547b5922 | |||
| c67c0789eb | |||
| cefe312ba1 | |||
| d8b1523161 | |||
| 61b02adc50 | |||
| 989ddbd688 | |||
| 96b670af49 | |||
| 359e02bad7 | |||
| 8aadcacc0b | |||
| 615efc7c86 | |||
| dd88104a81 | |||
| 5cb23725ae | |||
| 8c5c45a04c | |||
| 4a552e6326 | |||
| 1f0758708f | |||
| b8dec4268d | |||
| fc920a630f | |||
| ffeac8895d | |||
| cef9632607 | |||
| 76054dddb7 | |||
| 9dc8753a14 | |||
| a805d9a721 | |||
| 6c306f7633 | |||
| 05a86d5296 | |||
| 9422fd311f | |||
| 80360f3f51 | |||
| 321d93bff1 | |||
| 600d19c51b | |||
| ed933bca19 | |||
| a9ea590d24 | |||
| 275d39b59b | |||
| c24454ae70 | |||
| fbc38c78eb | |||
| b0db90de96 | |||
| eb96f9677e | |||
| 0a3b75c5f5 | |||
| 50562440bf | |||
| ce90c3c9ee | |||
| d4bdcd55e1 | |||
| 3f90faf0c9 | |||
| 3d35c5ceb1 | |||
| a674e842d0 | |||
| 23f0fbc376 | |||
| c63f4d68c8 | |||
| 518460af66 | |||
| 39f652de47 | |||
| 483afe462b | |||
| 1296fabe2c | |||
| dc2edd3e79 | |||
| e9c903f1ea | |||
| 83be954efd | |||
| f84bdee1ba | |||
| 5b074ceee5 | |||
| 40eed29527 | |||
| 3d3785a7f1 | |||
| 5df15b5724 | |||
| ee259e4229 | |||
| 36985f8da0 | |||
| eb0faf9602 | |||
| 899cc71990 | |||
| 7be18b4a80 | |||
| 0c9bb9d920 | |||
| 26e3daf5ad | |||
| 0af69f8cda | |||
| 86e26c9a44 | |||
| 541beb615b | |||
| 6646348e1a | |||
| c38d6dc959 | |||
| 924faa58b4 | |||
| 6be104e521 | |||
| e95204908a | |||
| e963fc4d6a | |||
| 1a75a71403 | |||
| 439fc86740 | |||
| 0010e882a7 | |||
| a022f18015 | |||
| cee9561259 | |||
| 3d0cd6f0dc | |||
| adb5928767 | |||
| 23c74bc67b | |||
| a22120fe94 | |||
| ae25eaf10c | |||
| adcfca966e | |||
| d8e34bd9b7 | |||
| 68046d0c08 | |||
| bc2bf1caeb | |||
| d551144841 | |||
| 84540d7aa2 | |||
| 57eedfc4f4 | |||
| 2718ade2bc | |||
| 95f36d4fa5 | |||
| 3accf4048e | |||
| eb05879148 | |||
| a882118c56 | |||
| 57d15ac6e7 | |||
| e3cfdf6982 | |||
| 017fe10762 | |||
| 7bb7a741c6 | |||
| 14351c5bf2 | |||
| 7ef3c87dbb | |||
| b2a2aa15c2 | |||
| 1ec2f8d537 | |||
| 6ded538546 | |||
| 0d1bc05419 | |||
| db2d7a4fdb | |||
| 3fa7dabaa8 | |||
| 1980f32bd6 | |||
| 9ab71ca0da | |||
| 3d06dddb72 | |||
| 9896205a06 | |||
| 8a626ef564 | |||
| 8429943569 | |||
| edd12d505d | |||
| 69f978f22b | |||
| 229c98309e | |||
| c2665462e5 | |||
| 73648bb2d8 | |||
| ba0daaa706 | |||
| dcc5697a48 | |||
| c20230509f | |||
| f03e0bee73 | |||
| c5cd97dd89 | |||
| c09d3e7bf4 | |||
| 46a394815c | |||
| a4b68b93f2 | |||
| e2e9b5d3b0 | |||
| b01e0fbbc2 | |||
| 4f0a3eec24 | |||
| 2a0311797c | |||
| 46e2b4e936 | |||
| 96ba8f35d4 | |||
| 9a5ddc5218 | |||
| 0b4cbcf409 | |||
| d0cd3a7415 | |||
| 3a167e3a75 | |||
| c9e21907ea | |||
| a422d0455e | |||
| 0bc3652fc7 | |||
| 672fc9fc4d | |||
| 796a0c3968 | |||
| ff36bd3d85 | |||
| 141299eb02 | |||
| efe05b3e13 | |||
| b1de429d2c | |||
| 5f51337a01 | |||
| fca7142a3c | |||
| bfa33bf5d3 | |||
| 235dae552a | |||
| a36c1ad406 | |||
| 32506a34ff | |||
| 3224d04df8 | |||
| c13c30b466 | |||
| 3de1719c17 | |||
| 0c1675c8b0 | |||
| 3d89c6b35d | |||
| 22982586f1 | |||
| 0d2c8dfeec | |||
| 305e965bcb | |||
| 906c7ef0fc | |||
| 2a7937e2ba | |||
| 2a5b8f53fe | |||
| c6e08b059b | |||
| 9a5216921c | |||
| 8a2078aa90 | |||
| 841a96691b | |||
| 8ef6f9dd7b | |||
| 5bc8a491a7 | |||
| 87952fdb8e | |||
| c474e137ac | |||
| 7b8b2f042c | |||
| 729e721b40 | |||
| e4ce017183 | |||
| bbccf9ddbf | |||
| a8425cfb47 | |||
| ef29ffeb21 | |||
| 3794d2417d | |||
| 70793236ab | |||
| 0a1ef1e59d | |||
| 44a43eae10 | |||
| 5b7f273165 | |||
| fa07e45eda | |||
| 90d587df13 | |||
| 793a6479ef | |||
| 47bef7a557 | |||
| 208ba2c116 | |||
| 42a8ac7096 | |||
| ccab715bbc | |||
| ee724f183a | |||
| c4d2aae0ed | |||
| c722665c32 | |||
| 8868bcf57a | |||
| 9e754cb0f1 | |||
| 802df73183 | |||
| 9331ebebcc | |||
| c64674c39e | |||
| 549a383cf0 | |||
| ce8ddd0c3f | |||
| 98490454b6 | |||
| bb334007cf | |||
| 9522c42460 | |||
| d165de0d4d | |||
| 5fb70c4c94 | |||
| 72cc92dc5c | |||
| de0fbb0445 | |||
| 12ebd422c6 | |||
| 7d715fe113 | |||
| 7ac156755b | |||
| 973ca6824c | |||
| 9c7956be9e | |||
| 4475454632 | |||
| f15825d2c6 | |||
| a440d8d812 | |||
| aaaddd03a6 | |||
| d62c701a43 | |||
| 79ad6f4564 | |||
| c60c7a7621 | |||
| 306bdf8869 | |||
| 37d3a8a861 | |||
| 7a29f6cff0 | |||
| c9e6862332 | |||
| b77e2f59ed | |||
| cac8582de1 | |||
| b4df51e483 | |||
| 06f4762144 | |||
| 357d085ffb | |||
| 2a50f9c8d4 | |||
| d54b708ba8 | |||
| fba20c9bd3 | |||
| 18ed444a63 | |||
| 2d6c43c260 | |||
| 71932da7e3 | |||
| a074c367ff | |||
| e6fb4ee265 | |||
| 7c336a6a82 | |||
| 71ae424aa8 | |||
| 88d6407092 | |||
| e15f245339 | |||
| eebf49ba72 | |||
| faa9df8735 | |||
| 8113182d5c | |||
| 3323c2730f | |||
| 6399f2b014 | |||
| 7218a68e89 | |||
| 7375074d2d | |||
| c9effb9b9f | |||
| ef73a284e3 | |||
| 28af376d10 | |||
| 48de1a01a9 | |||
| 209684d5a4 | |||
| 1405420935 | |||
| 48d277a3c4 | |||
| e0b9475378 | |||
| c561de33ee | |||
| d67d7168e2 | |||
| 3b3e7550f6 | |||
| 9b7a25d4a9 | |||
| bb0855b35a | |||
| e6f725dc2c | |||
| 3e4c2e4932 | |||
| 2f4f6894bd | |||
| 30c141ceb9 | |||
| d3abc1a2b4 | |||
| 465c87bd5a | |||
| cdf881a378 | |||
| e8c602b98f | |||
| d0d9a3a4f4 | |||
| 9e43072113 | |||
| 1bfbed0e02 | |||
| 0fd525d778 | |||
| 07bf64ae52 | |||
| cee45c1b15 | |||
| 68afbb37f4 | |||
| 7faca7066c | |||
| 3eaac057da | |||
| 3f1930b76e | |||
| afac1a2cc1 | |||
| 445696d660 | |||
| f454ac3150 | |||
| 82b6772ea4 | |||
| 662cbaf425 | |||
| 1556fad65a | |||
| 243e2e2b8a | |||
| 35111b39b8 | |||
| ba331024af | |||
| 4c655865e5 | |||
| 7aac8df2f2 | |||
| e98e62ec13 | |||
| eb3c1506f0 | |||
| 5bd4536372 | |||
| 7fa05238b8 | |||
| dd7449b8b5 | |||
| b7a0627d09 | |||
| c632125d82 | |||
| a509e112ea | |||
| 7c26b0abdb | |||
| f48ee00c2f | |||
| ced0ea515c | |||
| 8876328e4d | |||
| f4ff11a7ff | |||
| 77be7144c3 | |||
| 3337d38651 | |||
| fc3b0dcc80 | |||
| fc33cf6846 | |||
| 2c469a39c7 | |||
| d0001dc11d | |||
| 68719779d7 | |||
| 2ad6aa7886 | |||
| 75e3df6da2 | |||
| 753acc6971 | |||
| 0d258e8b55 | |||
| 3a60bee804 | |||
| b67e0002c1 | |||
| 0070119392 | |||
| 310fd1936b | |||
| 077bf28d26 | |||
| d97c6a7657 | |||
| 46b33854c9 | |||
| 5ee3686569 | |||
| d23144fd27 | |||
| e64eb631df | |||
| 129a62d4f1 | |||
| 8c9299c139 | |||
| 3e9b7120be | |||
| 675ba44e67 | |||
| 240b6aab13 | |||
| a1e8769cff | |||
| 73cba2cf13 | |||
| 49c761dc6d | |||
| 2a8d4c5bf5 | |||
| 2b8807eb73 | |||
| 2ef0e6b8f6 | |||
| d386563344 | |||
| 9ecc2ab15b | |||
| cb9101e0a0 | |||
| fd9adaf1de | |||
| af7008aa44 | |||
| d3a18fbe9a | |||
| b4b53aeb71 | |||
| c4b4a841d6 | |||
| 263d63aa56 | |||
| 8fcd1794a6 | |||
| 9b5ae95677 | |||
| 21c6d691d8 | |||
| 2e9eec156c | |||
| c9468adcfd | |||
| b345176bde | |||
| 879a4d49ae | |||
| 15594706c9 | |||
| 58e3f779f2 | |||
| 455d64fbd4 | |||
| 16ca677c1f | |||
| 1f1434b384 | |||
| f83370235f | |||
| 4961aff51b | |||
| 0ed3143006 | |||
| bc2b8b597c | |||
| ccc4c641c4 | |||
| 0ca8a4ad3b | |||
| 1931e3147d | |||
| 9d9ec192f1 | |||
| 586a000152 | |||
| 728f143e33 | |||
| f2e78dcc0b | |||
| a463609e4c | |||
| e05a305764 | |||
| a437c95fed | |||
| 8fe70978ff | |||
| 647fee31f8 | |||
| 8af6b6fa18 | |||
| f48f06e7b7 | |||
| 51b5a973e2 | |||
| 2bdae52fed | |||
| b3a66b3950 | |||
| a971fb6e94 | |||
| 036fa5cb24 | |||
| 81fe50d623 | |||
| b9b9bd8612 | |||
| 171a5d6476 | |||
| 00671a59a0 | |||
| ebca0398a7 | |||
| 58a405cc9f | |||
| 444fedd8d4 | |||
| f7137bf367 | |||
| 92a0ce991e | |||
| 1e7c60e171 | |||
| 2d2e3ed6a1 | |||
| 21a06df5e1 | |||
| c04efe8762 | |||
| 41071ee351 | |||
| 594049027b | |||
| b1ea291942 | |||
| 254c504465 | |||
| 9ceb6b79fd |
@@ -1,3 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: odin-lang
|
||||
patreon: gingerbill
|
||||
|
||||
@@ -11,8 +11,8 @@ assignees: ''
|
||||
|
||||
Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
|
||||
|
||||
* Operating System:
|
||||
* Please paste `odin version` output:
|
||||
* Operating System & Odin Version:
|
||||
* Please paste `odin report` output:
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
|
||||
+107
-14
@@ -1,52 +1,110 @@
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM
|
||||
run: sudo apt-get install llvm-11 clang-11 llvm
|
||||
- name: Download LLVM, botan
|
||||
run: sudo apt-get install llvm-11 clang-11 libbotan-2-dev botan
|
||||
- name: build odin
|
||||
run: make release
|
||||
run: ./build_odin.sh release
|
||||
- name: Odin version
|
||||
run: ./odin version
|
||||
timeout-minutes: 1
|
||||
- name: Odin report
|
||||
run: ./odin report
|
||||
timeout-minutes: 1
|
||||
- name: Odin check
|
||||
run: ./odin check examples/demo/demo.odin -vet
|
||||
run: ./odin check examples/demo -vet
|
||||
timeout-minutes: 10
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo/demo.odin
|
||||
run: ./odin run examples/demo
|
||||
timeout-minutes: 10
|
||||
- name: Odin run -debug
|
||||
run: ./odin run examples/demo -debug
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all
|
||||
run: ./odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
run: |
|
||||
cd tests/core
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Vendor library tests
|
||||
run: |
|
||||
cd tests/vendor
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Odin issues tests
|
||||
run: |
|
||||
cd tests/issues
|
||||
./run.sh
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for Linux i386
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for FreeBSD amd64
|
||||
run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for OpenBSD amd64
|
||||
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
|
||||
timeout-minutes: 10
|
||||
build_macOS:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM and setup PATH
|
||||
- name: Download LLVM, botan and setup PATH
|
||||
run: |
|
||||
brew install llvm@11
|
||||
brew install llvm@11 botan
|
||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
run: make release
|
||||
run: ./build_odin.sh release
|
||||
- name: Odin version
|
||||
run: ./odin version
|
||||
timeout-minutes: 1
|
||||
- name: Odin report
|
||||
run: ./odin report
|
||||
timeout-minutes: 1
|
||||
- name: Odin check
|
||||
run: ./odin check examples/demo/demo.odin -vet
|
||||
run: ./odin check examples/demo -vet
|
||||
timeout-minutes: 10
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo/demo.odin
|
||||
run: ./odin run examples/demo
|
||||
timeout-minutes: 10
|
||||
- name: Odin run -debug
|
||||
run: ./odin run examples/demo -debug
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all
|
||||
run: ./odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
run: |
|
||||
cd tests/core
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Vendor library tests
|
||||
run: |
|
||||
cd tests/vendor
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Odin issues tests
|
||||
run: |
|
||||
cd tests/issues
|
||||
./run.sh
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for Darwin arm64
|
||||
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for Linux arm64
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
||||
timeout-minutes: 10
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
@@ -57,17 +115,32 @@ jobs:
|
||||
- name: Odin version
|
||||
run: ./odin version
|
||||
timeout-minutes: 1
|
||||
- name: Odin report
|
||||
run: ./odin report
|
||||
timeout-minutes: 1
|
||||
- name: Odin check
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/demo/demo.odin -vet
|
||||
odin check examples/demo -vet
|
||||
timeout-minutes: 10
|
||||
- name: Odin run
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo/demo.odin
|
||||
odin run examples/demo
|
||||
timeout-minutes: 10
|
||||
- name: Odin run -debug
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo -debug
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
shell: cmd
|
||||
@@ -76,6 +149,13 @@ jobs:
|
||||
cd tests\core
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: Vendor library tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\vendor
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: core:math/big tests
|
||||
shell: cmd
|
||||
run: |
|
||||
@@ -83,3 +163,16 @@ jobs:
|
||||
cd tests\core\math\big
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: Odin issues tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\issues
|
||||
call run.bat
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for Windows 32bits
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style -target:windows_i386
|
||||
timeout-minutes: 10
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo/demo.odin
|
||||
odin run examples/demo
|
||||
- name: Copy artifacts
|
||||
run: |
|
||||
rm bin/llvm/windows/LLVM-C.lib
|
||||
@@ -41,11 +41,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: (Linux) Download LLVM
|
||||
run: sudo apt-get install llvm-11 clang-11 llvm
|
||||
run: sudo apt-get install llvm-11 clang-11
|
||||
- name: build odin
|
||||
run: make nightly
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo/demo.odin
|
||||
run: ./odin run examples/demo
|
||||
- name: Copy artifacts
|
||||
run: |
|
||||
mkdir dist
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
- name: build odin
|
||||
run: make nightly
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo/demo.odin
|
||||
run: ./odin run examples/demo
|
||||
- name: Copy artifacts
|
||||
run: |
|
||||
mkdir dist
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
python-version: '3.8.x'
|
||||
|
||||
- name: Install B2 CLI
|
||||
shell: bash
|
||||
@@ -127,16 +127,23 @@ jobs:
|
||||
BUCKET: ${{ secrets.B2_BUCKET }}
|
||||
DAYS_TO_KEEP: ${{ secrets.B2_DAYS_TO_KEEP }}
|
||||
run: |
|
||||
echo Authorizing B2 account
|
||||
b2 authorize-account "$APPID" "$APPKEY"
|
||||
|
||||
echo Uploading artifcates to B2
|
||||
chmod +x ./ci/upload_create_nightly.sh
|
||||
./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/
|
||||
./ci/upload_create_nightly.sh "$BUCKET" ubuntu-amd64 ubuntu_artifacts/
|
||||
./ci/upload_create_nightly.sh "$BUCKET" macos-amd64 macos_artifacts/
|
||||
|
||||
echo Deleting old artifacts in B2
|
||||
python3 ci/delete_old_binaries.py "$BUCKET" "$DAYS_TO_KEEP"
|
||||
|
||||
echo Creating nightly.json
|
||||
python3 ci/create_nightly_json.py "$BUCKET" > nightly.json
|
||||
|
||||
echo Uploading nightly.json
|
||||
b2 upload-file "$BUCKET" nightly.json nightly.json
|
||||
|
||||
echo Clear B2 account info
|
||||
b2 clear-account
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
name: "Close Stale Issues & PRs"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 21 * * *"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close Stale Issues
|
||||
uses: actions/stale@v4.1.0
|
||||
with:
|
||||
# stale-issue-message: |
|
||||
# Hello!
|
||||
#
|
||||
# I am marking this issue as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
|
||||
# - open a PR referencing and resolving the issue;
|
||||
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
|
||||
# - leave a comment and describe in detail why this issue is critical for your use case;
|
||||
# - open a new issue with updated details and a plan on resolving the issue.
|
||||
#
|
||||
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||
#
|
||||
# stale-pr-message: |
|
||||
# Hello!
|
||||
#
|
||||
# I am marking this PR as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
|
||||
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
|
||||
# - leave a comment and describe in detail why this issue is critical for your use case;
|
||||
#
|
||||
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||
|
||||
days-before-stale: 120
|
||||
days-before-close: 30
|
||||
exempt-draft-pr: true
|
||||
ascending: true
|
||||
operations-per-run: 1000
|
||||
exempt-issue-labels: "ignore"
|
||||
@@ -7,6 +7,9 @@
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# For macOS
|
||||
.DS_Store
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
@@ -266,6 +269,8 @@ bin/
|
||||
# - Linux/MacOS
|
||||
odin
|
||||
odin.dSYM
|
||||
*.bin
|
||||
demo.bin
|
||||
|
||||
# shared collection
|
||||
shared/
|
||||
@@ -276,3 +281,5 @@ shared/
|
||||
*.ll
|
||||
|
||||
*.sublime-workspace
|
||||
examples/bug/
|
||||
build.sh
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2016-2021 Ginger Bill. All rights reserved.
|
||||
Copyright (c) 2016-2022 Ginger Bill. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,53 +1,19 @@
|
||||
GIT_SHA=$(shell git rev-parse --short HEAD)
|
||||
DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value
|
||||
LDFLAGS=-pthread -ldl -lm -lstdc++
|
||||
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
|
||||
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
|
||||
CC=clang
|
||||
|
||||
OS=$(shell uname)
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
LLVM_CONFIG=llvm-config
|
||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
$(error "Requirement: llvm-config must be version 11")
|
||||
endif
|
||||
|
||||
LDFLAGS:=$(LDFLAGS) -liconv
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
||||
endif
|
||||
ifeq ($(OS), Linux)
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
ifneq ($(shell which llvm-config-11 2>/dev/null),)
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
else
|
||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
$(error "Requirement: llvm-config must be version 11")
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||
endif
|
||||
|
||||
all: debug demo
|
||||
all: debug
|
||||
|
||||
demo:
|
||||
./odin run examples/demo/demo.odin
|
||||
./odin run examples/demo/demo.odin -file
|
||||
|
||||
report:
|
||||
./odin report
|
||||
|
||||
debug:
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
|
||||
./build_odin.sh debug
|
||||
|
||||
release:
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 $(LDFLAGS) -o odin
|
||||
./build_odin.sh release
|
||||
|
||||
release_native:
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
|
||||
./build_odin.sh release-native
|
||||
|
||||
nightly:
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
|
||||
./build_odin.sh nightly
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://discord.gg/hnwN2Rj">
|
||||
<a href="https://discord.gg/odinlang">
|
||||
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
|
||||
</a>
|
||||
<a href="https://github.com/odin-lang/odin/actions">
|
||||
@@ -58,6 +58,10 @@ main :: proc() {
|
||||
|
||||
Instructions for downloading and installing the Odin compiler and libraries.
|
||||
|
||||
#### [Nightly Builds](https://odin-lang.org/docs/nightly/)
|
||||
|
||||
Get the latest nightly builds of Odin.
|
||||
|
||||
### Learning Odin
|
||||
|
||||
#### [Overview of Odin](https://odin-lang.org/docs/overview)
|
||||
@@ -68,6 +72,10 @@ An overview of the Odin programming language.
|
||||
|
||||
Answers to common questions about Odin.
|
||||
|
||||
#### [Packages](https://pkg.odin-lang.org/)
|
||||
|
||||
Documentation for all the official packages part of the [core](https://pkg.odin-lang.org/core/) and [vendor](https://pkg.odin-lang.org/vendor/) library collections.
|
||||
|
||||
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
|
||||
|
||||
A wiki maintained by the Odin community.
|
||||
@@ -76,15 +84,9 @@ A wiki maintained by the Odin community.
|
||||
|
||||
Get live support and talk with other odiners on the Odin Discord.
|
||||
|
||||
### References
|
||||
|
||||
#### [Language Specification](https://odin-lang.org/ref/spec)
|
||||
|
||||
The official Odin Language specification.
|
||||
|
||||
### Articles
|
||||
|
||||
#### [The Odin Blog](https://odin-lang.org/blog)
|
||||
#### [The Odin Blog](https://odin-lang.org/news/)
|
||||
|
||||
The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests.
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
NASM is now licensed under the 2-clause BSD license, also known as the
|
||||
simplified BSD license.
|
||||
|
||||
Copyright 1996-2010 the NASM Authors - All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Binary file not shown.
Binary file not shown.
@@ -58,7 +58,7 @@ set libs= ^
|
||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
set linker_flags=%linker_flags% -debug
|
||||
set linker_flags=%linker_flags% -debug /NATVIS:src\odin_compiler.natvis
|
||||
) else ( rem Release
|
||||
set linker_flags=%linker_flags% -debug
|
||||
)
|
||||
@@ -79,4 +79,4 @@ if %release_mode% EQU 0 odin run examples/demo
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
:end_of_build
|
||||
:end_of_build
|
||||
Executable
+162
@@ -0,0 +1,162 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
: ${CXX=clang++}
|
||||
: ${CPPFLAGS=}
|
||||
: ${CXXFLAGS=}
|
||||
: ${LDFLAGS=}
|
||||
: ${ODIN_VERSION=dev-$(date +"%Y-%m")}
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
|
||||
CXXFLAGS="$CXXFLAGS -std=c++14"
|
||||
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
|
||||
|
||||
GIT_SHA=$(git rev-parse --short HEAD || :)
|
||||
if [ "$GIT_SHA" ]; then CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\""; fi
|
||||
|
||||
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
|
||||
OS=$(uname)
|
||||
|
||||
panic() {
|
||||
printf "%s\n" "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
|
||||
|
||||
config_darwin() {
|
||||
ARCH=$(uname -m)
|
||||
: ${LLVM_CONFIG=llvm-config}
|
||||
|
||||
# allow for arm only llvm's with version 13
|
||||
if [ ARCH == arm64 ]; then
|
||||
MIN_LLVM_VERSION=("13.0.0")
|
||||
else
|
||||
# allow for x86 / amd64 all llvm versions begining from 11
|
||||
MIN_LLVM_VERSION=("11.1.0")
|
||||
fi
|
||||
|
||||
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||
if [ ARCH == arm64 ]; then
|
||||
panic "Requirement: llvm-config must be base version 13 for arm64"
|
||||
else
|
||||
panic "Requirement: llvm-config must be base version greater than 11 for amd64/x86"
|
||||
fi
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||
}
|
||||
|
||||
config_freebsd() {
|
||||
: ${LLVM_CONFIG=/usr/local/bin/llvm-config11}
|
||||
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
config_openbsd() {
|
||||
: ${LLVM_CONFIG=/usr/local/bin/llvm-config}
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
config_linux() {
|
||||
: ${LLVM_CONFIG=}
|
||||
|
||||
if [ ! "$LLVM_CONFIG" ]; then
|
||||
if which llvm-config > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config
|
||||
elif which llvm-config-11 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
elif which llvm-config-11-64 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config-11-64
|
||||
else
|
||||
panic "Unable to find LLVM-config"
|
||||
fi
|
||||
fi
|
||||
|
||||
MIN_LLVM_VERSION=("11.0.0")
|
||||
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||
echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version)
|
||||
panic "Requirement: llvm-config must be base version greater than 11"
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -ldl"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
build_odin() {
|
||||
case $1 in
|
||||
debug)
|
||||
EXTRAFLAGS="-g"
|
||||
;;
|
||||
release)
|
||||
EXTRAFLAGS="-O3"
|
||||
;;
|
||||
release-native)
|
||||
EXTRAFLAGS="-O3 -march=native"
|
||||
;;
|
||||
nightly)
|
||||
EXTRAFLAGS="-DNIGHTLY -O3"
|
||||
;;
|
||||
*)
|
||||
panic "Build mode unsupported!"
|
||||
esac
|
||||
|
||||
set -x
|
||||
$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||
set +x
|
||||
}
|
||||
|
||||
run_demo() {
|
||||
./odin run examples/demo/demo.odin -file
|
||||
}
|
||||
|
||||
case $OS in
|
||||
Linux)
|
||||
config_linux
|
||||
;;
|
||||
Darwin)
|
||||
config_darwin
|
||||
;;
|
||||
OpenBSD)
|
||||
config_openbsd
|
||||
;;
|
||||
FreeBSD)
|
||||
config_freebsd
|
||||
;;
|
||||
*)
|
||||
panic "Platform unsupported!"
|
||||
esac
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
build_odin debug
|
||||
run_demo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
case $1 in
|
||||
report)
|
||||
if [[ ! -f "./odin" ]]; then
|
||||
build_odin debug
|
||||
fi
|
||||
|
||||
./odin report
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
build_odin $1
|
||||
;;
|
||||
esac
|
||||
|
||||
run_demo
|
||||
exit 0
|
||||
else
|
||||
panic "Too many arguments!"
|
||||
fi
|
||||
@@ -8,6 +8,7 @@ import "core:intrinsics"
|
||||
|
||||
// Extra errors returns by scanning procedures
|
||||
Scanner_Extra_Error :: enum i32 {
|
||||
None,
|
||||
Negative_Advance,
|
||||
Advanced_Too_Far,
|
||||
Bad_Read_Count,
|
||||
@@ -15,7 +16,7 @@ Scanner_Extra_Error :: enum i32 {
|
||||
Too_Short,
|
||||
}
|
||||
|
||||
Scanner_Error :: union {
|
||||
Scanner_Error :: union #shared_nil {
|
||||
io.Error,
|
||||
Scanner_Extra_Error,
|
||||
}
|
||||
@@ -68,7 +69,7 @@ scanner_destroy :: proc(s: ^Scanner) {
|
||||
// Returns the first non-EOF error that was encounted by the scanner
|
||||
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
|
||||
switch s._err {
|
||||
case .EOF, .None:
|
||||
case .EOF, nil:
|
||||
return nil
|
||||
}
|
||||
return s._err
|
||||
@@ -93,10 +94,6 @@ scanner_text :: proc(s: ^Scanner) -> string {
|
||||
// scanner_scan advances the scanner
|
||||
scanner_scan :: proc(s: ^Scanner) -> bool {
|
||||
set_err :: proc(s: ^Scanner, err: Scanner_Error) {
|
||||
err := err
|
||||
if err == .None {
|
||||
err = nil
|
||||
}
|
||||
switch s._err {
|
||||
case nil, .EOF:
|
||||
s._err = err
|
||||
|
||||
+66
-66
@@ -1,90 +1,90 @@
|
||||
// This is purely for documentation
|
||||
package builtin
|
||||
|
||||
nil :: nil;
|
||||
false :: 0!==0;
|
||||
true :: 0==0;
|
||||
nil :: nil
|
||||
false :: 0!=0
|
||||
true :: 0==0
|
||||
|
||||
ODIN_OS :: ODIN_OS;
|
||||
ODIN_ARCH :: ODIN_ARCH;
|
||||
ODIN_ENDIAN :: ODIN_ENDIAN;
|
||||
ODIN_VENDOR :: ODIN_VENDOR;
|
||||
ODIN_VERSION :: ODIN_VERSION;
|
||||
ODIN_ROOT :: ODIN_ROOT;
|
||||
ODIN_DEBUG :: ODIN_DEBUG;
|
||||
ODIN_OS :: ODIN_OS
|
||||
ODIN_ARCH :: ODIN_ARCH
|
||||
ODIN_ENDIAN :: ODIN_ENDIAN
|
||||
ODIN_VENDOR :: ODIN_VENDOR
|
||||
ODIN_VERSION :: ODIN_VERSION
|
||||
ODIN_ROOT :: ODIN_ROOT
|
||||
ODIN_DEBUG :: ODIN_DEBUG
|
||||
|
||||
byte :: u8; // alias
|
||||
byte :: u8 // alias
|
||||
|
||||
bool :: bool;
|
||||
b8 :: b8;
|
||||
b16 :: b16;
|
||||
b32 :: b32;
|
||||
b64 :: b64;
|
||||
bool :: bool
|
||||
b8 :: b8
|
||||
b16 :: b16
|
||||
b32 :: b32
|
||||
b64 :: b64
|
||||
|
||||
i8 :: i8;
|
||||
u8 :: u8;
|
||||
i16 :: i16;
|
||||
u16 :: u16;
|
||||
i32 :: i32;
|
||||
u32 :: u32;
|
||||
i64 :: i64;
|
||||
u64 :: u64;
|
||||
i8 :: i8
|
||||
u8 :: u8
|
||||
i16 :: i16
|
||||
u16 :: u16
|
||||
i32 :: i32
|
||||
u32 :: u32
|
||||
i64 :: i64
|
||||
u64 :: u64
|
||||
|
||||
i128 :: i128;
|
||||
u128 :: u128;
|
||||
i128 :: i128
|
||||
u128 :: u128
|
||||
|
||||
rune :: rune;
|
||||
rune :: rune
|
||||
|
||||
f16 :: f16;
|
||||
f32 :: f32;
|
||||
f64 :: f64;
|
||||
f16 :: f16
|
||||
f32 :: f32
|
||||
f64 :: f64
|
||||
|
||||
complex32 :: complex32;
|
||||
complex64 :: complex64;
|
||||
complex128 :: complex128;
|
||||
complex32 :: complex32
|
||||
complex64 :: complex64
|
||||
complex128 :: complex128
|
||||
|
||||
quaternion64 :: quaternion64;
|
||||
quaternion128 :: quaternion128;
|
||||
quaternion256 :: quaternion256;
|
||||
quaternion64 :: quaternion64
|
||||
quaternion128 :: quaternion128
|
||||
quaternion256 :: quaternion256
|
||||
|
||||
int :: int;
|
||||
uint :: uint;
|
||||
uintptr :: uintptr;
|
||||
int :: int
|
||||
uint :: uint
|
||||
uintptr :: uintptr
|
||||
|
||||
rawptr :: rawptr;
|
||||
string :: string;
|
||||
cstring :: cstring;
|
||||
any :: any;
|
||||
rawptr :: rawptr
|
||||
string :: string
|
||||
cstring :: cstring
|
||||
any :: any
|
||||
|
||||
typeid :: typeid;
|
||||
typeid :: typeid
|
||||
|
||||
// Endian Specific Types
|
||||
i16le :: i16le;
|
||||
u16le :: u16le;
|
||||
i32le :: i32le;
|
||||
u32le :: u32le;
|
||||
i64le :: i64le;
|
||||
u64le :: u64le;
|
||||
i128le :: i128le;
|
||||
u128le :: u128le;
|
||||
i16le :: i16le
|
||||
u16le :: u16le
|
||||
i32le :: i32le
|
||||
u32le :: u32le
|
||||
i64le :: i64le
|
||||
u64le :: u64le
|
||||
i128le :: i128le
|
||||
u128le :: u128le
|
||||
|
||||
i16be :: i16be;
|
||||
u16be :: u16be;
|
||||
i32be :: i32be;
|
||||
u32be :: u32be;
|
||||
i64be :: i64be;
|
||||
u64be :: u64be;
|
||||
i128be :: i128be;
|
||||
u128be :: u128be;
|
||||
i16be :: i16be
|
||||
u16be :: u16be
|
||||
i32be :: i32be
|
||||
u32be :: u32be
|
||||
i64be :: i64be
|
||||
u64be :: u64be
|
||||
i128be :: i128be
|
||||
u128be :: u128be
|
||||
|
||||
|
||||
f16le :: f16le;
|
||||
f32le :: f32le;
|
||||
f64le :: f64le;
|
||||
f16le :: f16le
|
||||
f32le :: f32le
|
||||
f64le :: f64le
|
||||
|
||||
f16be :: f16be;
|
||||
f32be :: f32be;
|
||||
f64be :: f64be;
|
||||
f16be :: f16be
|
||||
f32be :: f32be
|
||||
f64be :: f64be
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -161,6 +161,10 @@ buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
|
||||
return copy(b.buf[m:], p), nil
|
||||
}
|
||||
|
||||
buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
|
||||
return buffer_write(b, ([^]byte)(ptr)[:size])
|
||||
}
|
||||
|
||||
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) {
|
||||
b.last_read = .Invalid
|
||||
m, ok := _buffer_try_grow(b, len(s))
|
||||
@@ -229,6 +233,10 @@ buffer_read :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
|
||||
return
|
||||
}
|
||||
|
||||
buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
|
||||
return buffer_read(b, ([^]byte)(ptr)[:size])
|
||||
}
|
||||
|
||||
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
|
||||
b.last_read = .Invalid
|
||||
|
||||
|
||||
+58
-39
@@ -5,13 +5,19 @@ import "core:unicode"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
clone :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> []byte {
|
||||
c := make([]byte, len(s)+1, allocator, loc)
|
||||
c := make([]byte, len(s), allocator, loc)
|
||||
copy(c, s)
|
||||
c[len(s)] = 0
|
||||
return c[:len(s)]
|
||||
}
|
||||
|
||||
ptr_from_slice :: proc(str: []byte) -> ^byte {
|
||||
clone_safe :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: mem.Allocator_Error) {
|
||||
c := make([]byte, len(s), allocator, loc) or_return
|
||||
copy(c, s)
|
||||
return c[:len(s)], nil
|
||||
}
|
||||
|
||||
ptr_from_slice :: ptr_from_bytes
|
||||
ptr_from_bytes :: proc(str: []byte) -> ^byte {
|
||||
d := transmute(mem.Raw_String)str
|
||||
return d.data
|
||||
}
|
||||
@@ -135,6 +141,25 @@ join :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> []byte
|
||||
return b
|
||||
}
|
||||
|
||||
join_safe :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> (data: []byte, err: mem.Allocator_Error) {
|
||||
if len(a) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
n := len(sep) * (len(a) - 1)
|
||||
for s in a {
|
||||
n += len(s)
|
||||
}
|
||||
|
||||
b := make([]byte, n, allocator) or_return
|
||||
i := copy(b, a[0])
|
||||
for s in a[1:] {
|
||||
i += copy(b[i:], sep)
|
||||
i += copy(b[i:], s)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte {
|
||||
if len(a) == 0 {
|
||||
return nil
|
||||
@@ -152,6 +177,24 @@ concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
concatenate_safe :: proc(a: [][]byte, allocator := context.allocator) -> (data: []byte, err: mem.Allocator_Error) {
|
||||
if len(a) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
n := 0
|
||||
for s in a {
|
||||
n += len(s)
|
||||
}
|
||||
b := make([]byte, n, allocator) or_return
|
||||
i := 0
|
||||
for s in a {
|
||||
i += copy(b[i:], s)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
||||
@private
|
||||
_split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator) -> [][]byte {
|
||||
s, n := s, n
|
||||
@@ -219,61 +262,37 @@ split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) ->
|
||||
|
||||
|
||||
@private
|
||||
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []byte, ok: bool) {
|
||||
s, n := s, n
|
||||
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if sep == nil {
|
||||
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save: int) -> (res: []byte, ok: bool) {
|
||||
if len(sep) == 0 {
|
||||
res = s[:]
|
||||
ok = true
|
||||
s^ = s[len(s):]
|
||||
return
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
n = count(s^, sep) + 1
|
||||
}
|
||||
|
||||
n -= 1
|
||||
|
||||
i := 0
|
||||
for ; i < n; i += 1 {
|
||||
m := index(s^, sep)
|
||||
if m < 0 {
|
||||
break
|
||||
}
|
||||
m := index(s^, sep)
|
||||
if m < 0 {
|
||||
// not found
|
||||
res = s[:]
|
||||
ok = len(res) != 0
|
||||
s^ = s[len(s):]
|
||||
} else {
|
||||
res = s[:m+sep_save]
|
||||
ok = true
|
||||
s^ = s[m+len(sep):]
|
||||
return
|
||||
}
|
||||
res = s[:]
|
||||
ok = res != nil
|
||||
s^ = s[len(s):]
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, 0, -1)
|
||||
}
|
||||
|
||||
split_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, 0, n)
|
||||
return _split_iterator(s, sep, 0)
|
||||
}
|
||||
|
||||
split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, len(sep), -1)
|
||||
return _split_iterator(s, sep, len(sep))
|
||||
}
|
||||
|
||||
split_after_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, len(sep), n)
|
||||
}
|
||||
|
||||
|
||||
|
||||
index_byte :: proc(s: []byte, c: byte) -> int {
|
||||
for i := 0; i < len(s); i += 1 {
|
||||
@@ -1143,7 +1162,7 @@ fields_proc :: proc(s: []byte, f: proc(rune) -> bool, allocator := context.alloc
|
||||
}
|
||||
|
||||
if start >= 0 {
|
||||
append(&subslices, s[start : end])
|
||||
append(&subslices, s[start : len(s)])
|
||||
}
|
||||
|
||||
return subslices[:]
|
||||
|
||||
+6
-4
@@ -3,22 +3,24 @@ package c
|
||||
import builtin "core:builtin"
|
||||
|
||||
char :: builtin.u8 // assuming -funsigned-char
|
||||
|
||||
schar :: builtin.i8
|
||||
short :: builtin.i16
|
||||
int :: builtin.i32
|
||||
long :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64
|
||||
long :: builtin.i32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.i64
|
||||
longlong :: builtin.i64
|
||||
|
||||
uchar :: builtin.u8
|
||||
ushort :: builtin.u16
|
||||
uint :: builtin.u32
|
||||
ulong :: builtin.u32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.u64
|
||||
ulong :: builtin.u32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.u64
|
||||
ulonglong :: builtin.u64
|
||||
|
||||
bool :: builtin.bool
|
||||
|
||||
size_t :: builtin.uint
|
||||
ssize_t :: builtin.int
|
||||
wchar_t :: builtin.u16 when (ODIN_OS == "windows") else builtin.u32
|
||||
wchar_t :: builtin.u16 when (ODIN_OS == .Windows) else builtin.u32
|
||||
|
||||
float :: builtin.f32
|
||||
double :: builtin.f64
|
||||
@@ -46,7 +48,7 @@ int_least64_t :: builtin.i64
|
||||
uint_least64_t :: builtin.u64
|
||||
|
||||
// Same on Windows, Linux, and FreeBSD
|
||||
when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
int_fast8_t :: builtin.i8
|
||||
uint_fast8_t :: builtin.u8
|
||||
int_fast16_t :: builtin.i32
|
||||
|
||||
@@ -519,7 +519,7 @@ join_adjacent_string_literals :: proc(cpp: ^Preprocessor, initial_tok: ^Token) {
|
||||
|
||||
|
||||
quote_string :: proc(s: string) -> []byte {
|
||||
b := strings.make_builder(0, len(s)+2)
|
||||
b := strings.builder_make(0, len(s)+2)
|
||||
io.write_quoted_string(strings.to_writer(&b), s, '"')
|
||||
return b.buf[:]
|
||||
}
|
||||
@@ -956,7 +956,7 @@ substitute_token :: proc(cpp: ^Preprocessor, tok: ^Token, args: ^Macro_Arg) -> ^
|
||||
continue
|
||||
}
|
||||
|
||||
if tok.lit == "__VA__OPT__" && tok.next.lit == "(" {
|
||||
if tok.lit == "__VA_OPT__" && tok.next.lit == "(" {
|
||||
opt_arg := read_macro_arg_one(cpp, &tok, tok.next.next, true)
|
||||
if has_varargs(args) {
|
||||
for t := opt_arg.tok; t.kind != .EOF; t = t.next {
|
||||
@@ -1276,7 +1276,7 @@ preprocess_internal :: proc(cpp: ^Preprocessor, tok: ^Token) -> ^Token {
|
||||
if start.file != nil {
|
||||
dir = filepath.dir(start.file.name)
|
||||
}
|
||||
path := filepath.join(dir, filename)
|
||||
path := filepath.join({dir, filename})
|
||||
if os.exists(path) {
|
||||
tok = include_file(cpp, tok, path, start.next.next)
|
||||
continue
|
||||
|
||||
@@ -2,8 +2,10 @@ package libc
|
||||
|
||||
// 7.3 Complex arithmetic
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package libc
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
+32
-3
@@ -2,8 +2,10 @@ package libc
|
||||
|
||||
// 7.5 Errors
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
@@ -12,7 +14,7 @@ when ODIN_OS == "windows" {
|
||||
// EDOM,
|
||||
// EILSEQ
|
||||
// ERANGE
|
||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@@ -25,7 +27,20 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .OpenBSD {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__errno")
|
||||
_get_errno :: proc() -> ^int ---
|
||||
}
|
||||
|
||||
EDOM :: 33
|
||||
EILSEQ :: 84
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@@ -38,6 +53,20 @@ when ODIN_OS == "windows" {
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__error")
|
||||
_get_errno :: proc() -> ^int ---
|
||||
}
|
||||
|
||||
// Unknown
|
||||
EDOM :: 33
|
||||
EILSEQ :: 92
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
// Odin has no way to make an identifier "errno" behave as a function call to
|
||||
// read the value, or to produce an lvalue such that you can assign a different
|
||||
// error value to errno. To work around this, just expose it as a function like
|
||||
|
||||
+13
-11
@@ -4,8 +4,10 @@ package libc
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
@@ -209,19 +211,19 @@ _signbitf :: #force_inline proc(x: float) -> int {
|
||||
return int(transmute(uint32_t)x >> 31)
|
||||
}
|
||||
|
||||
isfinite :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
||||
isfinite :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return fpclassify(x) == FP_INFINITE
|
||||
}
|
||||
|
||||
isinf :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
||||
isinf :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return fpclassify(x) > FP_INFINITE
|
||||
}
|
||||
|
||||
isnan :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
||||
isnan :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return fpclassify(x) == FP_NAN
|
||||
}
|
||||
|
||||
isnormal :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
||||
isnormal :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return fpclassify(x) == FP_NORMAL
|
||||
}
|
||||
|
||||
@@ -229,27 +231,27 @@ isnormal :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
||||
// implemented as the relational comparisons, as that would produce an invalid
|
||||
// "sticky" state that propagates and affects maths results. These need
|
||||
// to be implemented natively in Odin assuming isunordered to prevent that.
|
||||
isgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
||||
isgreater :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return !isunordered(x, y) && x > y
|
||||
}
|
||||
|
||||
isgreaterequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
||||
isgreaterequal :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return !isunordered(x, y) && x >= y
|
||||
}
|
||||
|
||||
isless :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
||||
isless :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return !isunordered(x, y) && x < y
|
||||
}
|
||||
|
||||
islessequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
||||
islessequal :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return !isunordered(x, y) && x <= y
|
||||
}
|
||||
|
||||
islessgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
||||
islessgreater :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
return !isunordered(x, y) && x <= y
|
||||
}
|
||||
|
||||
isunordered :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
||||
isunordered :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||
if isnan(x) {
|
||||
// Force evaluation of y to propagate exceptions for ordering semantics.
|
||||
// To ensure correct semantics of IEEE 754 this cannot be compiled away.
|
||||
|
||||
@@ -2,13 +2,14 @@ package libc
|
||||
|
||||
// 7.13 Nonlocal jumps
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.13.1 Save calling environment
|
||||
|
||||
+18
-3
@@ -2,8 +2,10 @@ package libc
|
||||
|
||||
// 7.14 Signal handling
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
@@ -19,7 +21,7 @@ foreign libc {
|
||||
raise :: proc(sig: int) -> int ---
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
SIG_ERR :: rawptr(~uintptr(0))
|
||||
SIG_DFL :: rawptr(uintptr(0))
|
||||
SIG_IGN :: rawptr(uintptr(1))
|
||||
@@ -32,7 +34,20 @@ when ODIN_OS == "windows" {
|
||||
SIGTERM :: 15
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||
SIG_ERR :: rawptr(~uintptr(0))
|
||||
SIG_DFL :: rawptr(uintptr(0))
|
||||
SIG_IGN :: rawptr(uintptr(1))
|
||||
|
||||
SIGABRT :: 6
|
||||
SIGFPE :: 8
|
||||
SIGILL :: 4
|
||||
SIGINT :: 2
|
||||
SIGSEGV :: 11
|
||||
SIGTERM :: 15
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
SIG_ERR :: rawptr(~uintptr(0))
|
||||
SIG_DFL :: rawptr(uintptr(0))
|
||||
SIG_IGN :: rawptr(uintptr(1))
|
||||
|
||||
+111
-146
@@ -47,29 +47,30 @@ kill_dependency :: #force_inline proc(value: $T) -> T {
|
||||
|
||||
// 7.17.4 Fences
|
||||
atomic_thread_fence :: #force_inline proc(order: memory_order) {
|
||||
switch (order) {
|
||||
case .relaxed:
|
||||
return
|
||||
case .consume:
|
||||
intrinsics.atomic_fence_acq()
|
||||
case .acquire:
|
||||
intrinsics.atomic_fence_acq()
|
||||
case .release:
|
||||
intrinsics.atomic_fence_rel()
|
||||
case .acq_rel:
|
||||
intrinsics.atomic_fence_acqrel()
|
||||
case .seq_cst:
|
||||
intrinsics.atomic_fence_acqrel()
|
||||
assert(order != .relaxed)
|
||||
assert(order != .consume)
|
||||
#partial switch order {
|
||||
case .acquire: intrinsics.atomic_thread_fence(.Acquire)
|
||||
case .release: intrinsics.atomic_thread_fence(.Release)
|
||||
case .acq_rel: intrinsics.atomic_thread_fence(.Acq_Rel)
|
||||
case .seq_cst: intrinsics.atomic_thread_fence(.Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
atomic_signal_fence :: #force_inline proc(order: memory_order) {
|
||||
atomic_thread_fence(order)
|
||||
assert(order != .relaxed)
|
||||
assert(order != .consume)
|
||||
#partial switch order {
|
||||
case .acquire: intrinsics.atomic_signal_fence(.Acquire)
|
||||
case .release: intrinsics.atomic_signal_fence(.Release)
|
||||
case .acq_rel: intrinsics.atomic_signal_fence(.Acq_Rel)
|
||||
case .seq_cst: intrinsics.atomic_signal_fence(.Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
// 7.17.5 Lock-free property
|
||||
atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool {
|
||||
return size_of(T) <= 8 && (intrinsics.type_is_integer(T) || intrinsics.type_is_pointer(T))
|
||||
return intrinsics.atomic_type_is_lock_free(T)
|
||||
}
|
||||
|
||||
// 7.17.6 Atomic integer types
|
||||
@@ -121,13 +122,10 @@ atomic_store_explicit :: #force_inline proc(object: ^$T, desired: T, order: memo
|
||||
assert(order != .acquire)
|
||||
assert(order != .acq_rel)
|
||||
|
||||
#partial switch (order) {
|
||||
case .relaxed:
|
||||
intrinsics.atomic_store_relaxed(object, desired)
|
||||
case .release:
|
||||
intrinsics.atomic_store_rel(object, desired)
|
||||
case .seq_cst:
|
||||
intrinsics.atomic_store(object, desired)
|
||||
#partial switch order {
|
||||
case .relaxed: intrinsics.atomic_store_explicit(object, desired, .Relaxed)
|
||||
case .release: intrinsics.atomic_store_explicit(object, desired, .Release)
|
||||
case .seq_cst: intrinsics.atomic_store_explicit(object, desired, .Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,36 +137,26 @@ atomic_load_explicit :: #force_inline proc(object: ^$T, order: memory_order) {
|
||||
assert(order != .release)
|
||||
assert(order != .acq_rel)
|
||||
|
||||
#partial switch (order) {
|
||||
case .relaxed:
|
||||
return intrinsics.atomic_load_relaxed(object)
|
||||
case .consume:
|
||||
return intrinsics.atomic_load_acq(object)
|
||||
case .acquire:
|
||||
return intrinsics.atomic_load_acq(object)
|
||||
case .seq_cst:
|
||||
return intrinsics.atomic_load(object)
|
||||
#partial switch order {
|
||||
case .relaxed: return intrinsics.atomic_load_explicit(object, .Relaxed)
|
||||
case .consume: return intrinsics.atomic_load_explicit(object, .Consume)
|
||||
case .acquire: return intrinsics.atomic_load_explicit(object, .Acquire)
|
||||
case .seq_cst: return intrinsics.atomic_load_explicit(object, .Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T {
|
||||
return intrinsics.atomic_xchg(object, desired)
|
||||
return intrinsics.atomic_exchange(object, desired)
|
||||
}
|
||||
|
||||
atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T {
|
||||
switch (order) {
|
||||
case .relaxed:
|
||||
return intrinsics.atomic_xchg_relaxed(object, desired)
|
||||
case .consume:
|
||||
return intrinsics.atomic_xchg_acq(object, desired)
|
||||
case .acquire:
|
||||
return intrinsics.atomic_xchg_acq(object, desired)
|
||||
case .release:
|
||||
return intrinsics.atomic_xchg_rel(object, desired)
|
||||
case .acq_rel:
|
||||
return intrinsics.atomic_xchg_acqrel(object, desired)
|
||||
case .seq_cst:
|
||||
return intrinsics.atomic_xchg(object, desired)
|
||||
switch order {
|
||||
case .relaxed: return intrinsics.atomic_exchange_explicit(object, desired, .Relaxed)
|
||||
case .consume: return intrinsics.atomic_exchange_explicit(object, desired, .Consume)
|
||||
case .acquire: return intrinsics.atomic_exchange_explicit(object, desired, .Acquire)
|
||||
case .release: return intrinsics.atomic_exchange_explicit(object, desired, .Release)
|
||||
case .acq_rel: return intrinsics.atomic_exchange_explicit(object, desired, .Acq_Rel)
|
||||
case .seq_cst: return intrinsics.atomic_exchange_explicit(object, desired, .Seq_Cst)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -189,102 +177,104 @@ atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: m
|
||||
// [success = seq_cst, failure = acquire] => failacq
|
||||
// [success = acquire, failure = relaxed] => acq_failrelaxed
|
||||
// [success = acq_rel, failure = relaxed] => acqrel_failrelaxed
|
||||
atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) {
|
||||
value, ok := intrinsics.atomic_cxchg(object, expected^, desired)
|
||||
atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
|
||||
value, ok := intrinsics.atomic_compare_exchange_strong(object, expected^, desired)
|
||||
if !ok { expected^ = value }
|
||||
return ok
|
||||
}
|
||||
|
||||
atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) {
|
||||
atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) -> bool {
|
||||
assert(failure != .release)
|
||||
assert(failure != .acq_rel)
|
||||
|
||||
value: T; ok: bool
|
||||
#partial switch (failure) {
|
||||
#partial switch failure {
|
||||
case .seq_cst:
|
||||
assert(success != .relaxed)
|
||||
#partial switch (success) {
|
||||
#partial switch success {
|
||||
case .seq_cst:
|
||||
value, ok := intrinsics.atomic_cxchg(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
|
||||
case .acquire:
|
||||
value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
|
||||
case .consume:
|
||||
value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Seq_Cst)
|
||||
case .release:
|
||||
value, ok := intrinsics.atomic_cxchg_rel(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Release, .Seq_Cst)
|
||||
case .acq_rel:
|
||||
value, ok := intrinsics.atomic_cxchg_acqrel(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
|
||||
}
|
||||
case .relaxed:
|
||||
assert(success != .release)
|
||||
#partial switch (success) {
|
||||
#partial switch success {
|
||||
case .relaxed:
|
||||
value, ok := intrinsics.atomic_cxchg_relaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Relaxed, .Relaxed)
|
||||
case .seq_cst:
|
||||
value, ok := intrinsics.atomic_cxchg_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
|
||||
case .acquire:
|
||||
value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Relaxed)
|
||||
case .consume:
|
||||
value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Relaxed)
|
||||
case .acq_rel:
|
||||
value, ok := intrinsics.atomic_cxchg_acqrel_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
|
||||
}
|
||||
case .consume:
|
||||
fallthrough
|
||||
assert(success == .seq_cst)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Consume)
|
||||
case .acquire:
|
||||
assert(success == .seq_cst)
|
||||
value, ok := intrinsics.atomic_cxchg_failacq(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
|
||||
|
||||
}
|
||||
if !ok { expected^ = value }
|
||||
return ok
|
||||
}
|
||||
|
||||
atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) {
|
||||
value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired)
|
||||
atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
|
||||
value, ok := intrinsics.atomic_compare_exchange_weak(object, expected^, desired)
|
||||
if !ok { expected^ = value }
|
||||
return ok
|
||||
}
|
||||
|
||||
atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) {
|
||||
atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) -> bool {
|
||||
assert(failure != .release)
|
||||
assert(failure != .acq_rel)
|
||||
|
||||
value: T; ok: bool
|
||||
#partial switch (failure) {
|
||||
#partial switch failure {
|
||||
case .seq_cst:
|
||||
assert(success != .relaxed)
|
||||
#partial switch (success) {
|
||||
#partial switch success {
|
||||
case .seq_cst:
|
||||
value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
|
||||
case .acquire:
|
||||
value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
|
||||
case .consume:
|
||||
value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Seq_Cst)
|
||||
case .release:
|
||||
value, ok := intrinsics.atomic_cxchgweak_rel(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Release, .Seq_Cst)
|
||||
case .acq_rel:
|
||||
value, ok := intrinsics.atomic_cxchgweak_acqrel(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
|
||||
}
|
||||
case .relaxed:
|
||||
assert(success != .release)
|
||||
#partial switch (success) {
|
||||
#partial switch success {
|
||||
case .relaxed:
|
||||
value, ok := intrinsics.atomic_cxchgweak_relaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Relaxed, .Relaxed)
|
||||
case .seq_cst:
|
||||
value, ok := intrinsics.atomic_cxchgweak_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
|
||||
case .acquire:
|
||||
value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Relaxed)
|
||||
case .consume:
|
||||
value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Relaxed)
|
||||
case .acq_rel:
|
||||
value, ok := intrinsics.atomic_cxchgweak_acqrel_failrelaxed(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
|
||||
}
|
||||
case .consume:
|
||||
fallthrough
|
||||
assert(success == .seq_cst)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Consume)
|
||||
case .acquire:
|
||||
assert(success == .seq_cst)
|
||||
value, ok := intrinsics.atomic_cxchgweak_failacq(object, expected^, desired)
|
||||
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
|
||||
|
||||
}
|
||||
if !ok { expected^ = value }
|
||||
@@ -297,19 +287,14 @@ atomic_fetch_add :: #force_inline proc(object: ^$T, operand: T) -> T {
|
||||
}
|
||||
|
||||
atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||
switch (order) {
|
||||
case .relaxed:
|
||||
return intrinsics.atomic_add_relaxed(object, operand)
|
||||
case .consume:
|
||||
return intrinsics.atomic_add_acq(object, operand)
|
||||
case .acquire:
|
||||
return intrinsics.atomic_add_acq(object, operand)
|
||||
case .release:
|
||||
return intrinsics.atomic_add_rel(object, operand)
|
||||
case .acq_rel:
|
||||
return intrinsics.atomic_add_acqrel(object, operand)
|
||||
case .seq_cst:
|
||||
return intrinsics.atomic_add(object, operand)
|
||||
switch order {
|
||||
case .relaxed: return intrinsics.atomic_add_explicit(object, operand, .Relaxed)
|
||||
case .consume: return intrinsics.atomic_add_explicit(object, operand, .Consume)
|
||||
case .acquire: return intrinsics.atomic_add_explicit(object, operand, .Acquire)
|
||||
case .release: return intrinsics.atomic_add_explicit(object, operand, .Release)
|
||||
case .acq_rel: return intrinsics.atomic_add_explicit(object, operand, .Acq_Rel)
|
||||
case: fallthrough
|
||||
case .seq_cst: return intrinsics.atomic_add_explicit(object, operand, .Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,19 +303,14 @@ atomic_fetch_sub :: #force_inline proc(object: ^$T, operand: T) -> T {
|
||||
}
|
||||
|
||||
atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||
switch (order) {
|
||||
case .relaxed:
|
||||
return intrinsics.atomic_sub_relaxed(object, operand)
|
||||
case .consume:
|
||||
return intrinsics.atomic_sub_acq(object, operand)
|
||||
case .acquire:
|
||||
return intrinsics.atomic_sub_acq(object, operand)
|
||||
case .release:
|
||||
return intrinsics.atomic_sub_rel(object, operand)
|
||||
case .acq_rel:
|
||||
return intrinsics.atomic_sub_acqrel(object, operand)
|
||||
case .seq_cst:
|
||||
return intrinsics.atomic_sub(object, operand)
|
||||
switch order {
|
||||
case .relaxed: return intrinsics.atomic_sub_explicit(object, operand, .Relaxed)
|
||||
case .consume: return intrinsics.atomic_sub_explicit(object, operand, .Consume)
|
||||
case .acquire: return intrinsics.atomic_sub_explicit(object, operand, .Acquire)
|
||||
case .release: return intrinsics.atomic_sub_explicit(object, operand, .Release)
|
||||
case .acq_rel: return intrinsics.atomic_sub_explicit(object, operand, .Acq_Rel)
|
||||
case: fallthrough
|
||||
case .seq_cst: return intrinsics.atomic_sub_explicit(object, operand, .Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,19 +319,14 @@ atomic_fetch_or :: #force_inline proc(object: ^$T, operand: T) -> T {
|
||||
}
|
||||
|
||||
atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||
switch (order) {
|
||||
case .relaxed:
|
||||
return intrinsics.atomic_or_relaxed(object, operand)
|
||||
case .consume:
|
||||
return intrinsics.atomic_or_acq(object, operand)
|
||||
case .acquire:
|
||||
return intrinsics.atomic_or_acq(object, operand)
|
||||
case .release:
|
||||
return intrinsics.atomic_or_rel(object, operand)
|
||||
case .acq_rel:
|
||||
return intrinsics.atomic_or_acqrel(object, operand)
|
||||
case .seq_cst:
|
||||
return intrinsics.atomic_or(object, operand)
|
||||
switch order {
|
||||
case .relaxed: return intrinsics.atomic_or_explicit(object, operand, .Relaxed)
|
||||
case .consume: return intrinsics.atomic_or_explicit(object, operand, .Consume)
|
||||
case .acquire: return intrinsics.atomic_or_explicit(object, operand, .Acquire)
|
||||
case .release: return intrinsics.atomic_or_explicit(object, operand, .Release)
|
||||
case .acq_rel: return intrinsics.atomic_or_explicit(object, operand, .Acq_Rel)
|
||||
case: fallthrough
|
||||
case .seq_cst: return intrinsics.atomic_or_explicit(object, operand, .Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,19 +335,14 @@ atomic_fetch_xor :: #force_inline proc(object: ^$T, operand: T) -> T {
|
||||
}
|
||||
|
||||
atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||
switch (order) {
|
||||
case .relaxed:
|
||||
return intrinsics.atomic_xor_relaxed(object, operand)
|
||||
case .consume:
|
||||
return intrinsics.atomic_xor_acq(object, operand)
|
||||
case .acquire:
|
||||
return intrinsics.atomic_xor_acq(object, operand)
|
||||
case .release:
|
||||
return intrinsics.atomic_xor_rel(object, operand)
|
||||
case .acq_rel:
|
||||
return intrinsics.atomic_xor_acqrel(object, operand)
|
||||
case .seq_cst:
|
||||
return intrinsics.atomic_xor(object, operand)
|
||||
switch order {
|
||||
case .relaxed: return intrinsics.atomic_xor_explicit(object, operand, .Relaxed)
|
||||
case .consume: return intrinsics.atomic_xor_explicit(object, operand, .Consume)
|
||||
case .acquire: return intrinsics.atomic_xor_explicit(object, operand, .Acquire)
|
||||
case .release: return intrinsics.atomic_xor_explicit(object, operand, .Release)
|
||||
case .acq_rel: return intrinsics.atomic_xor_explicit(object, operand, .Acq_Rel)
|
||||
case: fallthrough
|
||||
case .seq_cst: return intrinsics.atomic_xor_explicit(object, operand, .Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,19 +350,14 @@ atomic_fetch_and :: #force_inline proc(object: ^$T, operand: T) -> T {
|
||||
return intrinsics.atomic_and(object, operand)
|
||||
}
|
||||
atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||
switch (order) {
|
||||
case .relaxed:
|
||||
return intrinsics.atomic_and_relaxed(object, operand)
|
||||
case .consume:
|
||||
return intrinsics.atomic_and_acq(object, operand)
|
||||
case .acquire:
|
||||
return intrinsics.atomic_and_acq(object, operand)
|
||||
case .release:
|
||||
return intrinsics.atomic_and_rel(object, operand)
|
||||
case .acq_rel:
|
||||
return intrinsics.atomic_and_acqrel(object, operand)
|
||||
case .seq_cst:
|
||||
return intrinsics.atomic_and(object, operand)
|
||||
switch order {
|
||||
case .relaxed: return intrinsics.atomic_and_explicit(object, operand, .Relaxed)
|
||||
case .consume: return intrinsics.atomic_and_explicit(object, operand, .Consume)
|
||||
case .acquire: return intrinsics.atomic_and_explicit(object, operand, .Acquire)
|
||||
case .release: return intrinsics.atomic_and_explicit(object, operand, .Release)
|
||||
case .acq_rel: return intrinsics.atomic_and_explicit(object, operand, .Acq_Rel)
|
||||
case: fallthrough
|
||||
case .seq_cst: return intrinsics.atomic_and_explicit(object, operand, .Seq_Cst)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+88
-6
@@ -1,7 +1,9 @@
|
||||
package libc
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
@@ -11,7 +13,7 @@ when ODIN_OS == "windows" {
|
||||
FILE :: struct {}
|
||||
|
||||
// MSVCRT compatible.
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
_IOFBF :: 0x0000
|
||||
_IONBF :: 0x0004
|
||||
_IOLBF :: 0x0040
|
||||
@@ -46,7 +48,7 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
|
||||
// GLIBC and MUSL compatible.
|
||||
when ODIN_OS == "linux" {
|
||||
when ODIN_OS == .Linux {
|
||||
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
|
||||
|
||||
_IOFBF :: 0
|
||||
@@ -67,7 +69,7 @@ when ODIN_OS == "linux" {
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
TMP_MAX :: 10000
|
||||
TMP_MAX :: 308915776
|
||||
|
||||
foreign libc {
|
||||
stderr: ^FILE
|
||||
@@ -76,6 +78,86 @@ when ODIN_OS == "linux" {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
fpos_t :: distinct i64
|
||||
|
||||
_IOFBF :: 0
|
||||
_IOLBF :: 1
|
||||
_IONBF :: 1
|
||||
|
||||
BUFSIZ :: 1024
|
||||
|
||||
EOF :: int(-1)
|
||||
|
||||
FOPEN_MAX :: 20
|
||||
FILENAME_MAX :: 1024
|
||||
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
foreign libc {
|
||||
stderr: ^FILE
|
||||
stdin: ^FILE
|
||||
stdout: ^FILE
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .FreeBSD {
|
||||
fpos_t :: distinct i64
|
||||
|
||||
_IOFBF :: 0
|
||||
_IOLBF :: 1
|
||||
_IONBF :: 1
|
||||
|
||||
BUFSIZ :: 1024
|
||||
|
||||
EOF :: int(-1)
|
||||
|
||||
FOPEN_MAX :: 20
|
||||
FILENAME_MAX :: 1024
|
||||
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
foreign libc {
|
||||
stderr: ^FILE
|
||||
stdin: ^FILE
|
||||
stdout: ^FILE
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
fpos_t :: distinct i64
|
||||
|
||||
_IOFBF :: 0
|
||||
_IOLBF :: 1
|
||||
_IONBF :: 2
|
||||
|
||||
BUFSIZ :: 1024
|
||||
|
||||
EOF :: int(-1)
|
||||
|
||||
FOPEN_MAX :: 20
|
||||
|
||||
FILENAME_MAX :: 1024
|
||||
|
||||
L_tmpnam :: 1024
|
||||
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
TMP_MAX :: 308915776
|
||||
|
||||
foreign libc {
|
||||
@(link_name="__stderrp") stderr: ^FILE
|
||||
@(link_name="__stdinp") stdin: ^FILE
|
||||
@(link_name="__stdoutp") stdout: ^FILE
|
||||
}
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.21.4 Operations on files
|
||||
@@ -114,10 +196,10 @@ foreign libc {
|
||||
getc :: proc(stream: ^FILE) -> int ---
|
||||
getchar :: proc() -> int ---
|
||||
putc :: proc(c: int, stream: ^FILE) -> int ---
|
||||
putchar :: proc() -> int ---
|
||||
putchar :: proc(c: int) -> int ---
|
||||
puts :: proc(s: cstring) -> int ---
|
||||
ungetc :: proc(c: int, stream: ^FILE) -> int ---
|
||||
fread :: proc(ptr: rawptr, size: size_t, stream: ^FILE) -> size_t ---
|
||||
fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||
fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||
|
||||
// 7.21.9 File positioning functions
|
||||
|
||||
+22
-4
@@ -2,13 +2,15 @@ package libc
|
||||
|
||||
// 7.22 General utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
RAND_MAX :: 0x7fff
|
||||
|
||||
@(private="file")
|
||||
@@ -22,7 +24,7 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" {
|
||||
when ODIN_OS == .Linux {
|
||||
RAND_MAX :: 0x7fffffff
|
||||
|
||||
// GLIBC and MUSL only
|
||||
@@ -33,7 +35,23 @@ when ODIN_OS == "linux" {
|
||||
}
|
||||
|
||||
MB_CUR_MAX :: #force_inline proc() -> size_t {
|
||||
return __ctype_get_mb_cur_max()
|
||||
return size_t(__ctype_get_mb_cur_max())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
RAND_MAX :: 0x7fffffff
|
||||
|
||||
// GLIBC and MUSL only
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
___mb_cur_max :: proc() -> int ---
|
||||
}
|
||||
|
||||
MB_CUR_MAX :: #force_inline proc() -> size_t {
|
||||
return size_t(___mb_cur_max())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ import "core:runtime"
|
||||
|
||||
// 7.24 String handling
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ package libc
|
||||
thrd_start_t :: proc "c" (rawptr) -> int
|
||||
tss_dtor_t :: proc "c" (rawptr)
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc {
|
||||
"system:libucrt.lib",
|
||||
"system:msvcprt.lib"
|
||||
"system:msvcprt.lib",
|
||||
}
|
||||
|
||||
thrd_success :: 0 // _Thrd_success
|
||||
@@ -74,10 +74,10 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
|
||||
// GLIBC and MUSL compatible constants and types.
|
||||
when ODIN_OS == "linux" {
|
||||
when ODIN_OS == .Linux {
|
||||
foreign import libc {
|
||||
"system:c",
|
||||
"system:pthread"
|
||||
"system:pthread",
|
||||
}
|
||||
|
||||
thrd_success :: 0
|
||||
@@ -136,3 +136,8 @@ when ODIN_OS == "linux" {
|
||||
tss_set :: proc(key: tss_t, val: rawptr) -> int ---
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
// TODO: find out what this is meant to be!
|
||||
}
|
||||
|
||||
+13
-6
@@ -2,15 +2,17 @@ package libc
|
||||
|
||||
// 7.27 Date and time
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
||||
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
// 7.27.2 Time manipulation functions
|
||||
clock :: proc() -> clock_t ---
|
||||
@@ -43,7 +45,7 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.27.2 Time manipulation functions
|
||||
@@ -61,7 +63,12 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
|
||||
}
|
||||
|
||||
CLOCKS_PER_SEC :: 1000000
|
||||
when ODIN_OS == .OpenBSD {
|
||||
CLOCKS_PER_SEC :: 100
|
||||
} else {
|
||||
CLOCKS_PER_SEC :: 1000000
|
||||
}
|
||||
|
||||
TIME_UTC :: 1
|
||||
|
||||
time_t :: distinct i64
|
||||
@@ -75,7 +82,7 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
|
||||
tm :: struct {
|
||||
tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
|
||||
_: long,
|
||||
_: rawptr,
|
||||
tm_gmtoff: long,
|
||||
tm_zone: rawptr,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package libc
|
||||
import "core:c"
|
||||
|
||||
char :: c.char // assuming -funsigned-char
|
||||
|
||||
schar :: c.schar
|
||||
short :: c.short
|
||||
int :: c.int
|
||||
long :: c.long
|
||||
|
||||
@@ -2,8 +2,10 @@ package libc
|
||||
|
||||
// 7.28 Unicode utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package libc
|
||||
|
||||
// 7.29 Extended multibyte and wide character utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
+19
-5
@@ -2,20 +2,34 @@ package libc
|
||||
|
||||
// 7.30 Wide character classification and mapping utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
wctrans_t :: distinct wchar_t
|
||||
wctype_t :: distinct ushort
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" {
|
||||
wctrans_t :: distinct rawptr
|
||||
} else when ODIN_OS == .Linux {
|
||||
wctrans_t :: distinct intptr_t
|
||||
wctype_t :: distinct ulong
|
||||
|
||||
} else when ODIN_OS == .Darwin {
|
||||
wctrans_t :: distinct int
|
||||
wctype_t :: distinct u32
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
wctrans_t :: distinct rawptr
|
||||
wctype_t :: distinct rawptr
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
wctrans_t :: distinct int
|
||||
wctype_t :: distinct ulong
|
||||
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
|
||||
+20
-15
@@ -1,5 +1,3 @@
|
||||
package compress
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
@@ -8,9 +6,13 @@ package compress
|
||||
Jeroen van Rijn: Initial implementation, optimization.
|
||||
*/
|
||||
|
||||
|
||||
// package compress is a collection of utilities to aid with other compression packages
|
||||
package compress
|
||||
|
||||
import "core:io"
|
||||
import "core:image"
|
||||
import "core:bytes"
|
||||
import "core:runtime"
|
||||
|
||||
/*
|
||||
These settings bound how much compression algorithms will allocate for their output buffer.
|
||||
@@ -45,20 +47,18 @@ when size_of(uintptr) == 8 {
|
||||
}
|
||||
|
||||
|
||||
Error :: union {
|
||||
Error :: union #shared_nil {
|
||||
General_Error,
|
||||
Deflate_Error,
|
||||
ZLIB_Error,
|
||||
GZIP_Error,
|
||||
ZIP_Error,
|
||||
/*
|
||||
This is here because png.load will return a this type of error union,
|
||||
as it may involve an I/O error, a Deflate error, etc.
|
||||
*/
|
||||
image.Error,
|
||||
|
||||
runtime.Allocator_Error,
|
||||
}
|
||||
|
||||
General_Error :: enum {
|
||||
None = 0,
|
||||
File_Not_Found,
|
||||
Cannot_Open_File,
|
||||
File_Too_Short,
|
||||
@@ -69,7 +69,6 @@ General_Error :: enum {
|
||||
Incompatible_Options,
|
||||
Unimplemented,
|
||||
|
||||
|
||||
/*
|
||||
Memory errors
|
||||
*/
|
||||
@@ -78,6 +77,7 @@ General_Error :: enum {
|
||||
}
|
||||
|
||||
GZIP_Error :: enum {
|
||||
None = 0,
|
||||
Invalid_GZIP_Signature,
|
||||
Reserved_Flag_Set,
|
||||
Invalid_Extra_Data,
|
||||
@@ -102,6 +102,7 @@ GZIP_Error :: enum {
|
||||
}
|
||||
|
||||
ZIP_Error :: enum {
|
||||
None = 0,
|
||||
Invalid_ZIP_File_Signature,
|
||||
Unexpected_Signature,
|
||||
Insert_Next_Disk,
|
||||
@@ -109,6 +110,7 @@ ZIP_Error :: enum {
|
||||
}
|
||||
|
||||
ZLIB_Error :: enum {
|
||||
None = 0,
|
||||
Unsupported_Window_Size,
|
||||
FDICT_Unsupported,
|
||||
Unsupported_Compression_Level,
|
||||
@@ -116,6 +118,7 @@ ZLIB_Error :: enum {
|
||||
}
|
||||
|
||||
Deflate_Error :: enum {
|
||||
None = 0,
|
||||
Huffman_Bad_Sizes,
|
||||
Huffman_Bad_Code_Lengths,
|
||||
Inflate_Error,
|
||||
@@ -125,7 +128,6 @@ Deflate_Error :: enum {
|
||||
BType_3,
|
||||
}
|
||||
|
||||
|
||||
// General I/O context for ZLIB, LZW, etc.
|
||||
Context_Memory_Input :: struct #packed {
|
||||
input_data: []u8,
|
||||
@@ -141,7 +143,12 @@ Context_Memory_Input :: struct #packed {
|
||||
size_packed: i64,
|
||||
size_unpacked: i64,
|
||||
}
|
||||
#assert(size_of(Context_Memory_Input) == 64)
|
||||
when size_of(rawptr) == 8 {
|
||||
#assert(size_of(Context_Memory_Input) == 64)
|
||||
} else {
|
||||
// e.g. `-target:windows_i386`
|
||||
#assert(size_of(Context_Memory_Input) == 52)
|
||||
}
|
||||
|
||||
Context_Stream_Input :: struct #packed {
|
||||
input_data: []u8,
|
||||
@@ -176,8 +183,6 @@ Context_Stream_Input :: struct #packed {
|
||||
This simplifies end-of-stream handling where bits may be left in the bit buffer.
|
||||
*/
|
||||
|
||||
// TODO: Make these return compress.Error errors.
|
||||
|
||||
input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Error) {
|
||||
return i64(len(z.input_data)), nil
|
||||
}
|
||||
@@ -475,4 +480,4 @@ discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) {
|
||||
consume_bits_lsb(z, discard)
|
||||
}
|
||||
|
||||
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream};
|
||||
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}
|
||||
|
||||
@@ -45,7 +45,7 @@ main :: proc() {
|
||||
|
||||
if len(args) < 2 {
|
||||
stderr("No input file specified.\n")
|
||||
err := load(slice=TEST, buf=&buf, known_gzip_size=len(TEST))
|
||||
err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST))
|
||||
if err == nil {
|
||||
stdout("Displaying test vector: ")
|
||||
stdout(bytes.buffer_to_string(&buf))
|
||||
|
||||
@@ -66,7 +66,8 @@ OS :: enum u8 {
|
||||
_Unknown = 14,
|
||||
Unknown = 255,
|
||||
}
|
||||
OS_Name :: #partial [OS]string{
|
||||
OS_Name :: #sparse[OS]string{
|
||||
._Unknown = "",
|
||||
.FAT = "FAT",
|
||||
.Amiga = "Amiga",
|
||||
.VMS = "VMS/OpenVMS",
|
||||
@@ -99,9 +100,9 @@ E_GZIP :: compress.GZIP_Error
|
||||
E_ZLIB :: compress.ZLIB_Error
|
||||
E_Deflate :: compress.Deflate_Error
|
||||
|
||||
GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le))
|
||||
GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le))
|
||||
|
||||
load :: proc{load_from_slice, load_from_file, load_from_context}
|
||||
load :: proc{load_from_bytes, load_from_file, load_from_context}
|
||||
|
||||
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator
|
||||
@@ -111,16 +112,16 @@ load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_siz
|
||||
|
||||
err = E_General.File_Not_Found
|
||||
if ok {
|
||||
err = load_from_slice(data, buf, len(data), expected_output_size)
|
||||
err = load_from_bytes(data, buf, len(data), expected_output_size)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
load_from_slice :: proc(slice: []u8, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
||||
load_from_bytes :: proc(data: []byte, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
||||
buf := buf
|
||||
|
||||
z := &compress.Context_Memory_Input{
|
||||
input_data = slice,
|
||||
input_data = data,
|
||||
output = buf,
|
||||
}
|
||||
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator)
|
||||
@@ -135,7 +136,7 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
|
||||
|
||||
z.output = buf
|
||||
|
||||
if expected_output_size > GZIP_MAX_PAYLOAD_SIZE {
|
||||
if i64(expected_output_size) > i64(GZIP_MAX_PAYLOAD_SIZE) {
|
||||
return E_GZIP.Payload_Size_Exceeds_Max_Payload
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
This file was generated, so don't edit this by hand.
|
||||
Transliterated from https://github.com/Ed-von-Schleck/shoco/blob/master/shoco_model.h,
|
||||
which is an English word model.
|
||||
*/
|
||||
|
||||
// package shoco is an implementation of the shoco short string compressor
|
||||
package shoco
|
||||
|
||||
DEFAULT_MODEL :: Shoco_Model {
|
||||
min_char = 39,
|
||||
max_char = 122,
|
||||
characters_by_id = {
|
||||
'e', 'a', 'i', 'o', 't', 'h', 'n', 'r', 's', 'l', 'u', 'c', 'w', 'm', 'd', 'b', 'p', 'f', 'g', 'v', 'y', 'k', '-', 'H', 'M', 'T', '\'', 'B', 'x', 'I', 'W', 'L',
|
||||
},
|
||||
ids_by_character = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, 23, 29, -1, -1, 31, 24, -1, -1, -1, -1, -1, -1, 25, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 15, 11, 14, 0, 17, 18, 5, 2, -1, 21, 9, 13, 6, 3, 16, -1, 7, 8, 4, 10, 19, 12, 28, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
},
|
||||
successors_by_bigram = {
|
||||
7, 4, 12, -1, 6, -1, 1, 0, 3, 5, -1, 9, -1, 8, 2, -1, 15, 14, -1, 10, 11, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1,
|
||||
1, -1, 6, -1, 1, -1, 0, 3, 2, 4, 15, 11, -1, 9, 5, 10, 13, -1, 12, 8, 7, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
9, 11, -1, 4, 2, -1, 0, 8, 1, 5, -1, 6, -1, 3, 7, 15, -1, 12, 10, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 14, 7, 5, -1, 1, 2, 8, 9, 0, 15, 6, 4, 11, -1, 12, 3, -1, 10, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
2, 4, 3, 1, 5, 0, -1, 6, 10, 9, 7, 12, 11, -1, -1, -1, -1, 13, -1, -1, 8, -1, 15, -1, -1, -1, 14, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, -1, -1, 5, 9, 10, 6, -1, -1, 8, 15, 11, -1, 14, -1, -1, 7, -1, 13, -1, -1, -1, 12, -1, -1, -1, -1, -1,
|
||||
2, 8, 7, 4, 3, -1, 9, -1, 6, 11, -1, 5, -1, -1, 0, -1, -1, 14, 1, 15, 10, 12, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1,
|
||||
0, 3, 1, 2, 6, -1, 9, 8, 4, 12, 13, 10, -1, 11, 7, -1, -1, 15, 14, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 6, 3, 4, 1, 2, -1, -1, 5, 10, 7, 9, 11, 12, -1, -1, 8, 14, -1, -1, 15, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 6, 2, 5, 9, -1, -1, -1, 10, 1, 8, -1, 12, 14, 4, -1, 15, 7, -1, 13, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
8, 10, 9, 15, 1, -1, 4, 0, 3, 2, -1, 6, -1, 12, 11, 13, 7, 14, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 3, 6, 0, 4, 2, -1, 7, 13, 8, 9, 11, -1, -1, 15, -1, -1, -1, -1, -1, 10, 5, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
3, 0, 1, 4, -1, 2, 5, 6, 7, 8, -1, 14, -1, -1, 9, 15, -1, 12, -1, -1, -1, 10, 11, -1, -1, -1, 13, -1, -1, -1, -1, -1,
|
||||
0, 1, 3, 2, 15, -1, 12, -1, 7, 14, 4, -1, -1, 9, -1, 8, 5, 10, -1, -1, 6, -1, 13, -1, -1, -1, 11, -1, -1, -1, -1, -1,
|
||||
0, 3, 1, 2, -1, -1, 12, 6, 4, 9, 7, -1, -1, 14, 8, -1, -1, 15, 11, 13, 5, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 5, 7, 2, 10, 13, -1, 6, 8, 1, 3, -1, -1, 14, 15, 11, -1, -1, -1, 12, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 2, 6, 3, 7, 10, -1, 1, 9, 4, 8, -1, -1, 15, -1, 12, 5, -1, -1, -1, 11, -1, 13, -1, -1, -1, 14, -1, -1, -1, -1, -1,
|
||||
1, 3, 4, 0, 7, -1, 12, 2, 11, 8, 6, 13, -1, -1, -1, -1, -1, 5, -1, -1, 10, 15, 9, -1, -1, -1, 14, -1, -1, -1, -1, -1,
|
||||
1, 3, 5, 2, 13, 0, 9, 4, 7, 6, 8, -1, -1, 15, -1, 11, -1, -1, 10, -1, 14, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 2, 1, 3, -1, -1, -1, 6, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 11, 4, 0, 3, -1, 13, 12, 2, 7, -1, -1, 15, 10, 5, 8, 14, -1, -1, -1, -1, -1, 9, -1, -1, -1, 6, -1, -1, -1, -1, -1,
|
||||
0, 9, 2, 14, 15, 4, 1, 13, 3, 5, -1, -1, 10, -1, -1, -1, -1, 6, 12, -1, 7, -1, 8, -1, -1, -1, 11, -1, -1, -1, -1, -1,
|
||||
-1, 2, 14, -1, 1, 5, 8, 7, 4, 12, -1, 6, 9, 11, 13, 3, 10, 15, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 3, 2, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
4, 3, 1, 5, -1, -1, -1, 0, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
2, 8, 4, 1, -1, 0, -1, 6, -1, -1, 5, -1, 7, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
12, 5, -1, -1, 1, -1, -1, 7, 0, 3, -1, 2, -1, 4, 6, -1, -1, -1, -1, 8, -1, -1, 15, -1, 13, 9, -1, -1, -1, -1, -1, 11,
|
||||
1, 3, 2, 4, -1, -1, -1, 5, -1, 7, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1,
|
||||
5, 3, 4, 12, 1, 6, -1, -1, -1, -1, 8, 2, -1, -1, -1, -1, 0, 9, -1, -1, 11, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, 0, -1, 1, 12, 3, -1, -1, -1, -1, 5, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, 6, -1, 10,
|
||||
2, 3, 1, 4, -1, 0, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1,
|
||||
5, 1, 3, 0, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 9, -1, -1, 6, -1, 7,
|
||||
},
|
||||
successors_reversed = {
|
||||
's', 't', 'c', 'l', 'm', 'a', 'd', 'r', 'v', 'T', 'A', 'L', 'e', 'M', 'Y', '-',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'-', 't', 'a', 'b', 's', 'h', 'c', 'r', 'n', 'w', 'p', 'm', 'l', 'd', 'i', 'f',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'u', 'e', 'i', 'a', 'o', 'r', 'y', 'l', 'I', 'E', 'R', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'e', 'a', 'o', 'i', 'u', 'A', 'y', 'E', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
't', 'n', 'f', 's', '\'', 'm', 'I', 'N', 'A', 'E', 'L', 'Z', 'r', 'V', 'R', 'C',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'o', 'a', 'y', 'i', 'u', 'e', 'I', 'L', 'D', '\'', 'E', 'Y', '\x00', '\x00', '\x00', '\x00',
|
||||
'r', 'i', 'y', 'a', 'e', 'o', 'u', 'Y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'h', 'o', 'e', 'E', 'i', 'u', 'r', 'w', 'a', 'H', 'y', 'R', 'Z', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'h', 'i', 'e', 'a', 'o', 'r', 'I', 'y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'n', 't', 's', 'r', 'l', 'd', 'i', 'y', 'v', 'm', 'b', 'c', 'g', 'p', 'k', 'u',
|
||||
'e', 'l', 'o', 'u', 'y', 'a', 'r', 'i', 's', 'j', 't', 'b', 'v', 'h', 'm', 'd',
|
||||
'o', 'e', 'h', 'a', 't', 'k', 'i', 'r', 'l', 'u', 'y', 'c', 'q', 's', '-', 'd',
|
||||
'e', 'i', 'o', 'a', 's', 'y', 'r', 'u', 'd', 'l', '-', 'g', 'n', 'v', 'm', 'f',
|
||||
'r', 'n', 'd', 's', 'a', 'l', 't', 'e', 'm', 'c', 'v', 'y', 'i', 'x', 'f', 'p',
|
||||
'o', 'e', 'r', 'a', 'i', 'f', 'u', 't', 'l', '-', 'y', 's', 'n', 'c', '\'', 'k',
|
||||
'h', 'e', 'o', 'a', 'r', 'i', 'l', 's', 'u', 'n', 'g', 'b', '-', 't', 'y', 'm',
|
||||
'e', 'a', 'i', 'o', 't', 'r', 'u', 'y', 'm', 's', 'l', 'b', '\'', '-', 'f', 'd',
|
||||
'n', 's', 't', 'm', 'o', 'l', 'c', 'd', 'r', 'e', 'g', 'a', 'f', 'v', 'z', 'b',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'e', 'n', 'i', 's', 'h', 'l', 'f', 'y', '-', 'a', 'w', '\'', 'g', 'r', 'o', 't',
|
||||
'e', 'l', 'i', 'y', 'd', 'o', 'a', 'f', 'u', 't', 's', 'k', 'w', 'v', 'm', 'p',
|
||||
'e', 'a', 'o', 'i', 'u', 'p', 'y', 's', 'b', 'm', 'f', '\'', 'n', '-', 'l', 't',
|
||||
'd', 'g', 'e', 't', 'o', 'c', 's', 'i', 'a', 'n', 'y', 'l', 'k', '\'', 'f', 'v',
|
||||
'u', 'n', 'r', 'f', 'm', 't', 'w', 'o', 's', 'l', 'v', 'd', 'p', 'k', 'i', 'c',
|
||||
'e', 'r', 'a', 'o', 'l', 'p', 'i', 't', 'u', 's', 'h', 'y', 'b', '-', '\'', 'm',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'e', 'i', 'o', 'a', 's', 'y', 't', 'd', 'r', 'n', 'c', 'm', 'l', 'u', 'g', 'f',
|
||||
'e', 't', 'h', 'i', 'o', 's', 'a', 'u', 'p', 'c', 'l', 'w', 'm', 'k', 'f', 'y',
|
||||
'h', 'o', 'e', 'i', 'a', 't', 'r', 'u', 'y', 'l', 's', 'w', 'c', 'f', '\'', '-',
|
||||
'r', 't', 'l', 's', 'n', 'g', 'c', 'p', 'e', 'i', 'a', 'd', 'm', 'b', 'f', 'o',
|
||||
'e', 'i', 'a', 'o', 'y', 'u', 'r', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'a', 'i', 'h', 'e', 'o', 'n', 'r', 's', 'l', 'd', 'k', '-', 'f', '\'', 'c', 'b',
|
||||
'p', 't', 'c', 'a', 'i', 'e', 'h', 'q', 'u', 'f', '-', 'y', 'o', '\x00', '\x00', '\x00',
|
||||
'o', 'e', 's', 't', 'i', 'd', '\'', 'l', 'b', '-', 'm', 'a', 'r', 'n', 'p', 'w',
|
||||
},
|
||||
|
||||
character_count = 32,
|
||||
successor_count = 16,
|
||||
|
||||
max_successor_n = 7,
|
||||
packs = {
|
||||
{ 0x80000000, 1, 2, { 26, 24, 24, 24, 24, 24, 24, 24 }, { 15, 3, 0, 0, 0, 0, 0, 0 }, 0xc0, 0x80 },
|
||||
{ 0xc0000000, 2, 4, { 25, 22, 19, 16, 16, 16, 16, 16 }, { 15, 7, 7, 7, 0, 0, 0, 0 }, 0xe0, 0xc0 },
|
||||
{ 0xe0000000, 4, 8, { 23, 19, 15, 11, 8, 5, 2, 0 }, { 31, 15, 15, 15, 7, 7, 7, 3 }, 0xf0, 0xe0 },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
|
||||
An implementation of [shoco](https://github.com/Ed-von-Schleck/shoco) by Christian Schramm.
|
||||
*/
|
||||
|
||||
// package shoco is an implementation of the shoco short string compressor
|
||||
package shoco
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:compress"
|
||||
|
||||
Shoco_Pack :: struct {
|
||||
word: u32,
|
||||
bytes_packed: i8,
|
||||
bytes_unpacked: i8,
|
||||
offsets: [8]u16,
|
||||
masks: [8]i16,
|
||||
header_mask: u8,
|
||||
header: u8,
|
||||
}
|
||||
|
||||
Shoco_Model :: struct {
|
||||
min_char: u8,
|
||||
max_char: u8,
|
||||
characters_by_id: []u8,
|
||||
ids_by_character: [256]i16,
|
||||
successors_by_bigram: []i8,
|
||||
successors_reversed: []u8,
|
||||
|
||||
character_count: u8,
|
||||
successor_count: u8,
|
||||
max_successor_n: i8,
|
||||
packs: []Shoco_Pack,
|
||||
}
|
||||
|
||||
compress_bound :: proc(uncompressed_size: int) -> (worst_case_compressed_size: int) {
|
||||
// Worst case compression happens when input is non-ASCII (128-255)
|
||||
// Encoded as 0x00 + the byte in question.
|
||||
return uncompressed_size * 2
|
||||
}
|
||||
|
||||
decompress_bound :: proc(compressed_size: int, model := DEFAULT_MODEL) -> (maximum_decompressed_size: int) {
|
||||
// Best case compression is 2:1
|
||||
most: f64
|
||||
for pack in model.packs {
|
||||
val := f64(compressed_size) / f64(pack.bytes_packed) * f64(pack.bytes_unpacked)
|
||||
most = max(most, val)
|
||||
}
|
||||
return int(most)
|
||||
}
|
||||
|
||||
find_best_encoding :: proc(indices: []i16, n_consecutive: i8, model := DEFAULT_MODEL) -> (res: int) {
|
||||
for p := len(model.packs); p > 0; p -= 1 {
|
||||
pack := model.packs[p - 1]
|
||||
if n_consecutive >= pack.bytes_unpacked {
|
||||
have_index := true
|
||||
for i := 0; i < int(pack.bytes_unpacked); i += 1 {
|
||||
if indices[i] > pack.masks[i] {
|
||||
have_index = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if have_index {
|
||||
return p - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
validate_model :: proc(model: Shoco_Model) -> (int, compress.Error) {
|
||||
if len(model.characters_by_id) != int(model.character_count) {
|
||||
return 0, .Unknown_Compression_Method
|
||||
}
|
||||
|
||||
if len(model.successors_by_bigram) != int(model.character_count) * int(model.character_count) {
|
||||
return 0, .Unknown_Compression_Method
|
||||
}
|
||||
|
||||
if len(model.successors_reversed) != int(model.successor_count) * int(model.max_char - model.min_char) {
|
||||
return 0, .Unknown_Compression_Method
|
||||
}
|
||||
|
||||
// Model seems legit.
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Decompresses into provided buffer.
|
||||
decompress_slice_to_output_buffer :: proc(input: []u8, output: []u8, model := DEFAULT_MODEL) -> (size: int, err: compress.Error) {
|
||||
inp, inp_end := 0, len(input)
|
||||
out, out_end := 0, len(output)
|
||||
|
||||
validate_model(model) or_return
|
||||
|
||||
for inp < inp_end {
|
||||
val := transmute(i8)input[inp]
|
||||
mark := int(-1)
|
||||
|
||||
for val < 0 {
|
||||
val <<= 1
|
||||
mark += 1
|
||||
}
|
||||
|
||||
if mark > len(model.packs) {
|
||||
return out, .Unknown_Compression_Method
|
||||
}
|
||||
|
||||
if mark < 0 {
|
||||
if out >= out_end {
|
||||
return out, .Output_Too_Short
|
||||
}
|
||||
|
||||
// Ignore the sentinel value for non-ASCII chars
|
||||
if input[inp] == 0x00 {
|
||||
inp += 1
|
||||
if inp >= inp_end {
|
||||
return out, .Stream_Too_Short
|
||||
}
|
||||
}
|
||||
output[out] = input[inp]
|
||||
inp, out = inp + 1, out + 1
|
||||
|
||||
} else {
|
||||
pack := model.packs[mark]
|
||||
|
||||
if out + int(pack.bytes_unpacked) > out_end {
|
||||
return out, .Output_Too_Short
|
||||
} else if inp + int(pack.bytes_packed) > inp_end {
|
||||
return out, .Stream_Too_Short
|
||||
}
|
||||
|
||||
code := intrinsics.unaligned_load((^u32)(&input[inp]))
|
||||
when ODIN_ENDIAN == .Little {
|
||||
code = intrinsics.byte_swap(code)
|
||||
}
|
||||
|
||||
// Unpack the leading char
|
||||
offset := pack.offsets[0]
|
||||
mask := pack.masks[0]
|
||||
|
||||
last_chr := model.characters_by_id[(code >> offset) & u32(mask)]
|
||||
output[out] = last_chr
|
||||
|
||||
// Unpack the successor chars
|
||||
for i := 1; i < int(pack.bytes_unpacked); i += 1 {
|
||||
offset = pack.offsets[i]
|
||||
mask = pack.masks[i]
|
||||
|
||||
index_major := u32(last_chr - model.min_char) * u32(model.successor_count)
|
||||
index_minor := (code >> offset) & u32(mask)
|
||||
|
||||
last_chr = model.successors_reversed[index_major + index_minor]
|
||||
|
||||
output[out + i] = last_chr
|
||||
}
|
||||
|
||||
out += int(pack.bytes_unpacked)
|
||||
inp += int(pack.bytes_packed)
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (res: string, err: compress.Error) {
|
||||
context.allocator = allocator
|
||||
|
||||
if len(input) == 0 {
|
||||
return "", .Stream_Too_Short
|
||||
}
|
||||
|
||||
max_output_size := decompress_bound(len(input), model)
|
||||
|
||||
buf: [dynamic]u8
|
||||
if !resize(&buf, max_output_size) {
|
||||
return "", .Out_Of_Memory
|
||||
}
|
||||
|
||||
length, result := decompress_slice_to_output_buffer(input, buf[:])
|
||||
resize(&buf, length)
|
||||
return string(buf[:]), result
|
||||
}
|
||||
decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
|
||||
|
||||
compress_string_to_buffer :: proc(input: string, output: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (size: int, err: compress.Error) {
|
||||
inp, inp_end := 0, len(input)
|
||||
out, out_end := 0, len(output)
|
||||
output := output
|
||||
|
||||
validate_model(model) or_return
|
||||
|
||||
indices := make([]i16, model.max_successor_n + 1)
|
||||
defer delete(indices)
|
||||
|
||||
last_resort := false
|
||||
|
||||
encode: for inp < inp_end {
|
||||
if last_resort {
|
||||
last_resort = false
|
||||
|
||||
if input[inp] & 0x80 == 0x80 {
|
||||
// Non-ASCII case
|
||||
if out + 2 > out_end {
|
||||
return out, .Output_Too_Short
|
||||
}
|
||||
|
||||
// Put in a sentinel byte
|
||||
output[out] = 0x00
|
||||
out += 1
|
||||
} else {
|
||||
// An ASCII byte
|
||||
if out + 1 > out_end {
|
||||
return out, .Output_Too_Short
|
||||
}
|
||||
}
|
||||
output[out] = input[inp]
|
||||
out, inp = out + 1, inp + 1
|
||||
} else {
|
||||
// Find the longest string of known successors
|
||||
indices[0] = model.ids_by_character[input[inp]]
|
||||
last_chr_index := indices[0]
|
||||
|
||||
if last_chr_index < 0 {
|
||||
last_resort = true
|
||||
continue encode
|
||||
}
|
||||
|
||||
rest := inp_end - inp
|
||||
n_consecutive: i8 = 1
|
||||
for ; n_consecutive <= model.max_successor_n; n_consecutive += 1 {
|
||||
if inp_end > 0 && int(n_consecutive) == rest {
|
||||
break
|
||||
}
|
||||
|
||||
current_index := model.ids_by_character[input[inp + int(n_consecutive)]]
|
||||
if current_index < 0 { // '\0' is always -1
|
||||
break
|
||||
}
|
||||
|
||||
successor_index := model.successors_by_bigram[last_chr_index * i16(model.character_count) + current_index]
|
||||
if successor_index < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
indices[n_consecutive] = i16(successor_index)
|
||||
last_chr_index = current_index
|
||||
}
|
||||
|
||||
if n_consecutive < 2 {
|
||||
last_resort = true
|
||||
continue encode
|
||||
}
|
||||
|
||||
pack_n := find_best_encoding(indices, n_consecutive)
|
||||
if pack_n >= 0 {
|
||||
if out + int(model.packs[pack_n].bytes_packed) > out_end {
|
||||
return out, .Output_Too_Short
|
||||
}
|
||||
|
||||
pack := model.packs[pack_n]
|
||||
code := pack.word
|
||||
|
||||
for i := 0; i < int(pack.bytes_unpacked); i += 1 {
|
||||
code |= u32(indices[i]) << pack.offsets[i]
|
||||
}
|
||||
|
||||
// In the little-endian world, we need to swap what's in the register to match the memory representation.
|
||||
when ODIN_ENDIAN == .Little {
|
||||
code = intrinsics.byte_swap(code)
|
||||
}
|
||||
out_ptr := raw_data(output[out:])
|
||||
|
||||
switch pack.bytes_packed {
|
||||
case 4:
|
||||
intrinsics.unaligned_store(transmute(^u32)out_ptr, code)
|
||||
case 2:
|
||||
intrinsics.unaligned_store(transmute(^u16)out_ptr, u16(code))
|
||||
case 1:
|
||||
intrinsics.unaligned_store(transmute(^u8)out_ptr, u8(code))
|
||||
case:
|
||||
return out, .Unknown_Compression_Method
|
||||
}
|
||||
|
||||
out += int(pack.bytes_packed)
|
||||
inp += int(pack.bytes_unpacked)
|
||||
} else {
|
||||
last_resort = true
|
||||
continue encode
|
||||
}
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := context.allocator) -> (output: []u8, err: compress.Error) {
|
||||
context.allocator = allocator
|
||||
|
||||
if len(input) == 0 {
|
||||
return {}, .Stream_Too_Short
|
||||
}
|
||||
|
||||
max_output_size := compress_bound(len(input))
|
||||
|
||||
buf: [dynamic]u8
|
||||
if !resize(&buf, max_output_size) {
|
||||
return {}, .Out_Of_Memory
|
||||
}
|
||||
|
||||
length, result := compress_string_to_buffer(input, buf[:])
|
||||
resize(&buf, length)
|
||||
return buf[:length], result
|
||||
}
|
||||
compress :: proc{compress_string_to_buffer, compress_string}
|
||||
@@ -47,10 +47,10 @@ Options :: struct {
|
||||
level: u8,
|
||||
}
|
||||
|
||||
Error :: compress.Error
|
||||
E_General :: compress.General_Error
|
||||
E_ZLIB :: compress.ZLIB_Error
|
||||
E_Deflate :: compress.Deflate_Error
|
||||
Error :: compress.Error
|
||||
General_Error :: compress.General_Error
|
||||
ZLIB_Error :: compress.ZLIB_Error
|
||||
Deflate_Error :: compress.Deflate_Error
|
||||
|
||||
DEFLATE_MAX_CHUNK_SIZE :: 65535
|
||||
DEFLATE_MAX_LITERAL_SIZE :: 65535
|
||||
@@ -111,9 +111,9 @@ ZFAST_MASK :: ((1 << ZFAST_BITS) - 1)
|
||||
*/
|
||||
Huffman_Table :: struct {
|
||||
fast: [1 << ZFAST_BITS]u16,
|
||||
firstcode: [16]u16,
|
||||
firstcode: [17]u16,
|
||||
maxcode: [17]int,
|
||||
firstsymbol: [16]u16,
|
||||
firstsymbol: [17]u16,
|
||||
size: [288]u8,
|
||||
value: [288]u16,
|
||||
}
|
||||
@@ -244,7 +244,7 @@ allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_T
|
||||
@(optimization_mode="speed")
|
||||
build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
sizes: [HUFFMAN_MAX_BITS+1]int
|
||||
next_code: [HUFFMAN_MAX_BITS]int
|
||||
next_code: [HUFFMAN_MAX_BITS+1]int
|
||||
|
||||
k := int(0)
|
||||
|
||||
@@ -256,21 +256,21 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
}
|
||||
sizes[0] = 0
|
||||
|
||||
for i in 1..<(HUFFMAN_MAX_BITS+1) {
|
||||
for i in 1 ..< HUFFMAN_MAX_BITS {
|
||||
if sizes[i] > (1 << uint(i)) {
|
||||
return E_Deflate.Huffman_Bad_Sizes
|
||||
return .Huffman_Bad_Sizes
|
||||
}
|
||||
}
|
||||
code := int(0)
|
||||
|
||||
for i in 1..<HUFFMAN_MAX_BITS {
|
||||
for i in 1 ..= HUFFMAN_MAX_BITS {
|
||||
next_code[i] = code
|
||||
z.firstcode[i] = u16(code)
|
||||
z.firstsymbol[i] = u16(k)
|
||||
code = code + sizes[i]
|
||||
if sizes[i] != 0 {
|
||||
if code - 1 >= (1 << u16(i)) {
|
||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
||||
return .Huffman_Bad_Code_Lengths
|
||||
}
|
||||
}
|
||||
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i))
|
||||
@@ -314,15 +314,15 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
||||
s += 1
|
||||
}
|
||||
if s >= 16 {
|
||||
return 0, E_Deflate.Bad_Huffman_Code
|
||||
return 0, .Bad_Huffman_Code
|
||||
}
|
||||
// code size is s, so:
|
||||
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s])
|
||||
if b >= size_of(t.size) {
|
||||
return 0, E_Deflate.Bad_Huffman_Code
|
||||
return 0, .Bad_Huffman_Code
|
||||
}
|
||||
if t.size[b] != s {
|
||||
return 0, E_Deflate.Bad_Huffman_Code
|
||||
return 0, .Bad_Huffman_Code
|
||||
}
|
||||
|
||||
compress.consume_bits_lsb(z, s)
|
||||
@@ -335,11 +335,11 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
||||
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
|
||||
if z.num_bits < 16 {
|
||||
if z.num_bits > 63 {
|
||||
return 0, E_ZLIB.Code_Buffer_Malformed
|
||||
return 0, .Code_Buffer_Malformed
|
||||
}
|
||||
compress.refill_lsb(z)
|
||||
if z.num_bits > 63 {
|
||||
return 0, E_General.Stream_Too_Short
|
||||
return 0, .Stream_Too_Short
|
||||
}
|
||||
}
|
||||
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK]
|
||||
@@ -361,7 +361,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
||||
if value < 256 {
|
||||
e := write_byte(z, u8(value))
|
||||
if e != .None {
|
||||
return E_General.Output_Too_Short
|
||||
return .Output_Too_Short
|
||||
}
|
||||
} else {
|
||||
if value == 256 {
|
||||
@@ -377,7 +377,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
||||
|
||||
value, e = decode_huffman(z, z_offset)
|
||||
if e != nil {
|
||||
return E_Deflate.Bad_Huffman_Code
|
||||
return .Bad_Huffman_Code
|
||||
}
|
||||
|
||||
distance := Z_DIST_BASE[value]
|
||||
@@ -387,7 +387,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
||||
|
||||
if z.bytes_written < i64(distance) {
|
||||
// Distance is longer than we've decoded so far.
|
||||
return E_Deflate.Bad_Distance
|
||||
return .Bad_Distance
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -405,14 +405,14 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
||||
c := z.output.buf[z.bytes_written - i64(distance)]
|
||||
e := repl_byte(z, length, c)
|
||||
if e != .None {
|
||||
return E_General.Output_Too_Short
|
||||
return .Output_Too_Short
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if length > 0 {
|
||||
e := repl_bytes(z, length, distance)
|
||||
if e != .None {
|
||||
return E_General.Output_Too_Short
|
||||
return .Output_Too_Short
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,25 +432,25 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
||||
if !raw {
|
||||
size, size_err := compress.input_size(ctx)
|
||||
if size < 6 || size_err != nil {
|
||||
return E_General.Stream_Too_Short
|
||||
return .Stream_Too_Short
|
||||
}
|
||||
|
||||
cmf, _ := compress.read_u8(ctx)
|
||||
|
||||
method := Compression_Method(cmf & 0xf)
|
||||
if method != .DEFLATE {
|
||||
return E_General.Unknown_Compression_Method
|
||||
return .Unknown_Compression_Method
|
||||
}
|
||||
|
||||
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
|
||||
return E_ZLIB.Unsupported_Window_Size
|
||||
return .Unsupported_Window_Size
|
||||
}
|
||||
flg, _ := compress.read_u8(ctx)
|
||||
|
||||
fcheck := flg & 0x1f
|
||||
fcheck_computed := (cmf << 8 | flg) & 0x1f
|
||||
if fcheck != fcheck_computed {
|
||||
return E_General.Checksum_Failed
|
||||
return .Checksum_Failed
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -458,7 +458,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
||||
They're application specific and PNG doesn't use them.
|
||||
*/
|
||||
if fdict := (flg >> 5) & 1; fdict != 0 {
|
||||
return E_ZLIB.FDICT_Unsupported
|
||||
return .FDICT_Unsupported
|
||||
}
|
||||
|
||||
// flevel := Compression_Level((flg >> 6) & 3);
|
||||
@@ -485,7 +485,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
||||
output_hash := hash.adler32(ctx.output.buf[:])
|
||||
|
||||
if output_hash != u32(adler) {
|
||||
return E_General.Checksum_Failed
|
||||
return .Checksum_Failed
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -538,23 +538,24 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
final = compress.read_bits_lsb(z, 1)
|
||||
type = compress.read_bits_lsb(z, 2)
|
||||
|
||||
// fmt.printf("Final: %v | Type: %v\n", final, type);
|
||||
// fmt.printf("Final: %v | Type: %v\n", final, type)
|
||||
|
||||
switch type {
|
||||
case 0:
|
||||
// fmt.printf("Method 0: STORED\n")
|
||||
// Uncompressed block
|
||||
|
||||
// Discard bits until next byte boundary
|
||||
compress.discard_to_next_byte_lsb(z)
|
||||
|
||||
uncompressed_len := i16(compress.read_bits_lsb(z, 16))
|
||||
length_check := i16(compress.read_bits_lsb(z, 16))
|
||||
uncompressed_len := u16(compress.read_bits_lsb(z, 16))
|
||||
length_check := u16(compress.read_bits_lsb(z, 16))
|
||||
|
||||
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
|
||||
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check)
|
||||
|
||||
|
||||
if ~uncompressed_len != length_check {
|
||||
return E_Deflate.Len_Nlen_Mismatch
|
||||
return .Len_Nlen_Mismatch
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -567,10 +568,12 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
write_byte(z, u8(lit))
|
||||
uncompressed_len -= 1
|
||||
}
|
||||
assert(uncompressed_len == 0)
|
||||
|
||||
case 3:
|
||||
return E_Deflate.BType_3
|
||||
return .BType_3
|
||||
case:
|
||||
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
|
||||
// fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type)
|
||||
if type == 1 {
|
||||
// Use fixed code lengths.
|
||||
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return
|
||||
@@ -601,7 +604,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
c = decode_huffman(z, codelength_ht) or_return
|
||||
|
||||
if c < 0 || c >= 19 {
|
||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
||||
return .Huffman_Bad_Code_Lengths
|
||||
}
|
||||
if c < 16 {
|
||||
lencodes[n] = u8(c)
|
||||
@@ -613,7 +616,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
case 16:
|
||||
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3)
|
||||
if n == 0 {
|
||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
||||
return .Huffman_Bad_Code_Lengths
|
||||
}
|
||||
fill = lencodes[n - 1]
|
||||
case 17:
|
||||
@@ -621,11 +624,11 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
case 18:
|
||||
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11)
|
||||
case:
|
||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
||||
return .Huffman_Bad_Code_Lengths
|
||||
}
|
||||
|
||||
if ntot - n < u32(c) {
|
||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
||||
return .Huffman_Bad_Code_Lengths
|
||||
}
|
||||
|
||||
nc := n + u32(c)
|
||||
@@ -636,7 +639,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
}
|
||||
|
||||
if n != ntot {
|
||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
||||
return .Huffman_Bad_Code_Lengths
|
||||
}
|
||||
|
||||
build_huffman(z_repeat, lencodes[:hlit]) or_return
|
||||
@@ -674,4 +677,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
|
||||
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
|
||||
}
|
||||
|
||||
inflate :: proc{inflate_from_context, inflate_from_byte_array};
|
||||
inflate :: proc{inflate_from_context, inflate_from_byte_array}
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
package container
|
||||
|
||||
import "core:mem"
|
||||
import "core:runtime"
|
||||
|
||||
Array :: struct($T: typeid) {
|
||||
data: ^T,
|
||||
len: int,
|
||||
cap: int,
|
||||
allocator: mem.Allocator,
|
||||
}
|
||||
|
||||
ARRAY_DEFAULT_CAPACITY :: 16
|
||||
|
||||
/*
|
||||
array_init :: proc {
|
||||
array_init_none,
|
||||
array_init_len,
|
||||
array_init_len_cap,
|
||||
}
|
||||
array_init
|
||||
array_delete
|
||||
array_len
|
||||
array_cap
|
||||
array_space
|
||||
array_slice
|
||||
array_get
|
||||
array_get_ptr
|
||||
array_set
|
||||
array_reserve
|
||||
array_resize
|
||||
array_push = array_append :: proc{
|
||||
array_push_back,
|
||||
array_push_back_elems,
|
||||
}
|
||||
array_push_front
|
||||
array_pop_back
|
||||
array_pop_front
|
||||
array_consume
|
||||
array_trim
|
||||
array_clear
|
||||
array_clone
|
||||
array_set_capacity
|
||||
array_grow
|
||||
*/
|
||||
|
||||
|
||||
array_init_none :: proc(a: ^$A/Array, allocator := context.allocator) {
|
||||
array_init_len_cap(a, 0, ARRAY_DEFAULT_CAPACITY, allocator)
|
||||
}
|
||||
array_init_len :: proc(a: ^$A/Array, len: int, allocator := context.allocator) {
|
||||
array_init_len_cap(a, len, len, allocator)
|
||||
}
|
||||
array_init_len_cap :: proc(a: ^$A/Array($T), len: int, cap: int, allocator := context.allocator) {
|
||||
a.allocator = allocator
|
||||
a.data = (^T)(mem.alloc(size_of(T)*cap, align_of(T), a.allocator))
|
||||
a.len = len
|
||||
a.cap = cap
|
||||
}
|
||||
|
||||
array_init :: proc{array_init_none, array_init_len, array_init_len_cap}
|
||||
|
||||
array_delete :: proc(a: $A/Array) {
|
||||
mem.free(a.data, a.allocator)
|
||||
}
|
||||
|
||||
array_len :: proc(a: $A/Array) -> int {
|
||||
return a.len
|
||||
}
|
||||
|
||||
array_cap :: proc(a: $A/Array) -> int {
|
||||
return a.cap
|
||||
}
|
||||
|
||||
array_space :: proc(a: $A/Array) -> int {
|
||||
return a.cap - a.len
|
||||
}
|
||||
|
||||
array_slice :: proc(a: $A/Array($T)) -> []T {
|
||||
s := mem.Raw_Slice{a.data, a.len}
|
||||
return transmute([]T)s
|
||||
}
|
||||
|
||||
array_cap_slice :: proc(a: $A/Array($T)) -> []T {
|
||||
s := mem.Raw_Slice{a.data, a.cap}
|
||||
return transmute([]T)s
|
||||
}
|
||||
|
||||
array_get :: proc(a: $A/Array($T), index: int, loc := #caller_location) -> T {
|
||||
runtime.bounds_check_error_loc(loc, index, array_len(a))
|
||||
return (^T)(uintptr(a.data) + size_of(T)*uintptr(index))^
|
||||
}
|
||||
array_get_ptr :: proc(a: $A/Array($T), index: int, loc := #caller_location) -> ^T {
|
||||
runtime.bounds_check_error_loc(loc, index, array_len(a))
|
||||
return (^T)(uintptr(a.data) + size_of(T)*uintptr(index))
|
||||
}
|
||||
|
||||
array_set :: proc(a: ^$A/Array($T), index: int, item: T, loc := #caller_location) {
|
||||
runtime.bounds_check_error_loc(loc, index, array_len(a^))
|
||||
(^T)(uintptr(a.data) + size_of(T)*uintptr(index))^ = item
|
||||
}
|
||||
|
||||
|
||||
array_reserve :: proc(a: ^$A/Array, capacity: int) {
|
||||
if capacity > a.len {
|
||||
array_set_capacity(a, capacity)
|
||||
}
|
||||
}
|
||||
|
||||
array_resize :: proc(a: ^$A/Array, length: int) {
|
||||
if length > a.len {
|
||||
array_set_capacity(a, length)
|
||||
}
|
||||
a.len = length
|
||||
}
|
||||
|
||||
|
||||
|
||||
array_push_back :: proc(a: ^$A/Array($T), item: T) {
|
||||
if array_space(a^) == 0 {
|
||||
array_grow(a)
|
||||
}
|
||||
|
||||
a.len += 1
|
||||
array_set(a, a.len-1, item)
|
||||
}
|
||||
|
||||
array_push_front :: proc(a: ^$A/Array($T), item: T) {
|
||||
if array_space(a^) == 0 {
|
||||
array_grow(a)
|
||||
}
|
||||
|
||||
a.len += 1
|
||||
data := array_slice(a^)
|
||||
copy(data[1:], data[:])
|
||||
data[0] = item
|
||||
}
|
||||
|
||||
array_pop_back :: proc(a: ^$A/Array($T), loc := #caller_location) -> T {
|
||||
assert(condition=a.len > 0, loc=loc)
|
||||
item := array_get(a^, a.len-1)
|
||||
a.len -= 1
|
||||
return item
|
||||
}
|
||||
|
||||
array_pop_front :: proc(a: ^$A/Array($T), loc := #caller_location) -> T {
|
||||
assert(condition=a.len > 0, loc=loc)
|
||||
item := array_get(a^, 0)
|
||||
s := array_slice(a^)
|
||||
copy(s[:], s[1:])
|
||||
a.len -= 1
|
||||
return item
|
||||
}
|
||||
|
||||
|
||||
array_consume :: proc(a: ^$A/Array($T), count: int, loc := #caller_location) {
|
||||
assert(condition=a.len >= count, loc=loc)
|
||||
a.len -= count
|
||||
}
|
||||
|
||||
|
||||
array_trim :: proc(a: ^$A/Array($T)) {
|
||||
array_set_capacity(a, a.len)
|
||||
}
|
||||
|
||||
array_clear :: proc(a: ^$A/Array($T)) {
|
||||
array_resize(a, 0)
|
||||
}
|
||||
|
||||
array_clone :: proc(a: $A/Array($T), allocator := context.allocator) -> A {
|
||||
res: A
|
||||
array_init(&res, array_len(a), array_len(a), allocator)
|
||||
copy(array_slice(res), array_slice(a))
|
||||
return res
|
||||
}
|
||||
|
||||
array_push_back_elems :: proc(a: ^$A/Array($T), items: ..T) {
|
||||
if array_space(a^) < len(items) {
|
||||
array_grow(a, a.len + len(items))
|
||||
}
|
||||
offset := a.len
|
||||
data := array_cap_slice(a^)
|
||||
n := copy(data[a.len:], items)
|
||||
a.len += n
|
||||
}
|
||||
|
||||
array_push :: proc{array_push_back, array_push_back_elems}
|
||||
array_append :: proc{array_push_back, array_push_back_elems}
|
||||
|
||||
array_set_capacity :: proc(a: ^$A/Array($T), new_capacity: int) {
|
||||
if new_capacity == a.cap {
|
||||
return
|
||||
}
|
||||
|
||||
if new_capacity < a.len {
|
||||
array_resize(a, new_capacity)
|
||||
}
|
||||
|
||||
new_data: ^T
|
||||
if new_capacity > 0 {
|
||||
if a.allocator.procedure == nil {
|
||||
a.allocator = context.allocator
|
||||
}
|
||||
new_data = (^T)(mem.alloc(size_of(T)*new_capacity, align_of(T), a.allocator))
|
||||
if new_data != nil {
|
||||
mem.copy(new_data, a.data, size_of(T)*a.len)
|
||||
}
|
||||
}
|
||||
mem.free(a.data, a.allocator)
|
||||
a.data = new_data
|
||||
a.cap = new_capacity
|
||||
}
|
||||
array_grow :: proc(a: ^$A/Array, min_capacity: int = 0) {
|
||||
new_capacity := max(array_len(a^)*2 + 8, min_capacity)
|
||||
array_set_capacity(a, new_capacity)
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
package dynamic_bit_array
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:mem"
|
||||
|
||||
/*
|
||||
Note that these constants are dependent on the backing being a u64.
|
||||
*/
|
||||
@(private="file")
|
||||
INDEX_SHIFT :: 6
|
||||
|
||||
@(private="file")
|
||||
INDEX_MASK :: 63
|
||||
|
||||
@(private="file")
|
||||
NUM_BITS :: 64
|
||||
|
||||
Bit_Array :: struct {
|
||||
bits: [dynamic]u64,
|
||||
bias: int,
|
||||
max_index: int,
|
||||
free_pointer: bool,
|
||||
}
|
||||
|
||||
Bit_Array_Iterator :: struct {
|
||||
array: ^Bit_Array,
|
||||
word_idx: int,
|
||||
bit_idx: uint,
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - the array to iterate over
|
||||
|
||||
Out:
|
||||
- it: ^Bit_Array_Iterator - the iterator that holds iteration state
|
||||
*/
|
||||
make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
|
||||
return Bit_Array_Iterator { array = ba }
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||
|
||||
Out:
|
||||
- set: bool - the state of the bit at `index`
|
||||
- index: int - the next bit of the Bit_Array referenced by `it`.
|
||||
- ok: bool - `true` if the iterator returned a valid index,
|
||||
`false` if there were no more bits
|
||||
*/
|
||||
iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
|
||||
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
|
||||
if index > it.array.max_index { return false, 0, false }
|
||||
|
||||
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||
set = (word >> it.bit_idx & 1) == 1
|
||||
|
||||
it.bit_idx += 1
|
||||
if it.bit_idx >= NUM_BITS {
|
||||
it.bit_idx = 0
|
||||
it.word_idx += 1
|
||||
}
|
||||
|
||||
return set, index, true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||
|
||||
Out:
|
||||
- index: int - the next set bit of the Bit_Array referenced by `it`.
|
||||
- ok: bool - `true` if the iterator returned a valid index,
|
||||
`false` if there were no more bits set
|
||||
*/
|
||||
iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||
return iterate_internal_(it, true)
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||
|
||||
Out:
|
||||
- index: int - the next unset bit of the Bit_Array referenced by `it`.
|
||||
- ok: bool - `true` if the iterator returned a valid index,
|
||||
`false` if there were no more unset bits
|
||||
*/
|
||||
iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||
return iterate_internal_(it, false)
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
|
||||
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||
when ! ITERATE_SET_BITS { word = ~word }
|
||||
|
||||
// if the word is empty or we have already gone over all the bits in it,
|
||||
// b.bit_idx is greater than the index of any set bit in the word,
|
||||
// meaning that word >> b.bit_idx == 0.
|
||||
for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
|
||||
it.word_idx += 1
|
||||
it.bit_idx = 0
|
||||
word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||
when ! ITERATE_SET_BITS { word = ~word }
|
||||
}
|
||||
|
||||
// if we are iterating the set bits, reaching the end of the array means we have no more bits to check
|
||||
when ITERATE_SET_BITS {
|
||||
if it.word_idx >= len(it.array.bits) {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// reaching here means that the word has some set bits
|
||||
it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
|
||||
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
|
||||
|
||||
it.bit_idx += 1
|
||||
if it.bit_idx >= NUM_BITS {
|
||||
it.bit_idx = 0
|
||||
it.word_idx += 1
|
||||
}
|
||||
return index, index <= it.array.max_index
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||
- index: The bit index. Can be an enum member.
|
||||
|
||||
Out:
|
||||
- res: The bit you're interested in.
|
||||
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
|
||||
|
||||
The `ok` return value may be ignored.
|
||||
*/
|
||||
get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) {
|
||||
idx := int(index) - ba.bias
|
||||
|
||||
if ba == nil || int(index) < ba.bias { return false, false }
|
||||
context.allocator = allocator
|
||||
|
||||
leg_index := idx >> INDEX_SHIFT
|
||||
bit_index := idx & INDEX_MASK
|
||||
|
||||
/*
|
||||
If we `get` a bit that doesn't fit in the Bit Array, it's naturally `false`.
|
||||
This early-out prevents unnecessary resizing.
|
||||
*/
|
||||
if leg_index + 1 > len(ba.bits) { return false, true }
|
||||
|
||||
val := u64(1 << uint(bit_index))
|
||||
res = ba.bits[leg_index] & val == val
|
||||
|
||||
return res, true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||
- index: The bit index. Can be an enum member.
|
||||
|
||||
Out:
|
||||
- ok: Whether or not we managed to set requested bit.
|
||||
|
||||
`set` automatically resizes the Bit Array to accommodate the requested index if needed.
|
||||
*/
|
||||
set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
|
||||
|
||||
idx := int(index) - ba.bias
|
||||
|
||||
if ba == nil || int(index) < ba.bias { return false }
|
||||
context.allocator = allocator
|
||||
|
||||
leg_index := idx >> INDEX_SHIFT
|
||||
bit_index := idx & INDEX_MASK
|
||||
|
||||
resize_if_needed(ba, leg_index) or_return
|
||||
|
||||
ba.max_index = max(idx, ba.max_index)
|
||||
ba.bits[leg_index] |= 1 << uint(bit_index)
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||
- index: The bit index. Can be an enum member.
|
||||
|
||||
Out:
|
||||
- ok: Whether or not we managed to unset requested bit.
|
||||
|
||||
`unset` automatically resizes the Bit Array to accommodate the requested index if needed.
|
||||
*/
|
||||
unset :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
|
||||
|
||||
idx := int(index) - ba.bias
|
||||
|
||||
if ba == nil || int(index) < ba.bias { return false }
|
||||
context.allocator = allocator
|
||||
|
||||
leg_index := idx >> INDEX_SHIFT
|
||||
bit_index := idx & INDEX_MASK
|
||||
|
||||
resize_if_needed(ba, leg_index) or_return
|
||||
|
||||
ba.max_index = max(idx, ba.max_index)
|
||||
ba.bits[leg_index] &= ~(1 << uint(bit_index))
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
||||
*/
|
||||
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
|
||||
context.allocator = allocator
|
||||
size_in_bits := max_index - min_index
|
||||
|
||||
if size_in_bits < 1 { return {}, false }
|
||||
|
||||
legs := size_in_bits >> INDEX_SHIFT
|
||||
|
||||
res = new(Bit_Array)
|
||||
res.bias = min_index
|
||||
res.max_index = max_index
|
||||
res.free_pointer = true
|
||||
return res, resize_if_needed(res, legs)
|
||||
}
|
||||
|
||||
/*
|
||||
Sets all bits to `false`.
|
||||
*/
|
||||
clear :: proc(ba: ^Bit_Array) {
|
||||
if ba == nil { return }
|
||||
mem.zero_slice(ba.bits[:])
|
||||
}
|
||||
|
||||
/*
|
||||
Releases the memory used by the Bit Array.
|
||||
*/
|
||||
destroy :: proc(ba: ^Bit_Array) {
|
||||
if ba == nil { return }
|
||||
delete(ba.bits)
|
||||
if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack.
|
||||
free(ba)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Resizes the Bit Array. For internal use.
|
||||
If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
|
||||
*/
|
||||
@(private="file")
|
||||
resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocator) -> (ok: bool) {
|
||||
if ba == nil { return false }
|
||||
|
||||
context.allocator = allocator
|
||||
|
||||
if legs + 1 > len(ba.bits) {
|
||||
resize(&ba.bits, legs + 1)
|
||||
}
|
||||
return len(ba.bits) > legs
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package dynamic_bit_array
|
||||
|
||||
/*
|
||||
The Bit Array can be used in several ways:
|
||||
|
||||
-- By default you don't need to instantiate a Bit Array:
|
||||
|
||||
package test
|
||||
|
||||
import "core:fmt"
|
||||
import "core:container/bit_array"
|
||||
|
||||
main :: proc() {
|
||||
using bit_array
|
||||
|
||||
bits: Bit_Array
|
||||
|
||||
// returns `true`
|
||||
fmt.println(set(&bits, 42))
|
||||
|
||||
// returns `false`, `false`, because this Bit Array wasn't created to allow negative indices.
|
||||
was_set, was_retrieved := get(&bits, -1)
|
||||
fmt.println(was_set, was_retrieved)
|
||||
destroy(&bits)
|
||||
}
|
||||
|
||||
-- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation:
|
||||
|
||||
package test
|
||||
|
||||
import "core:fmt"
|
||||
import "core:container/bit_array"
|
||||
|
||||
main :: proc() {
|
||||
Foo :: enum int {
|
||||
Negative_Test = -42,
|
||||
Bar = 420,
|
||||
Leaves = 69105,
|
||||
}
|
||||
|
||||
using bit_array
|
||||
|
||||
bits := create(int(max(Foo)), int(min(Foo)))
|
||||
defer destroy(bits)
|
||||
|
||||
fmt.printf("Set(Bar): %v\n", set(bits, Foo.Bar))
|
||||
fmt.printf("Get(Bar): %v, %v\n", get(bits, Foo.Bar))
|
||||
fmt.printf("Set(Negative_Test): %v\n", set(bits, Foo.Negative_Test))
|
||||
fmt.printf("Get(Leaves): %v, %v\n", get(bits, Foo.Leaves))
|
||||
fmt.printf("Get(Negative_Test): %v, %v\n", get(bits, Foo.Negative_Test))
|
||||
fmt.printf("Freed.\n")
|
||||
}
|
||||
*/
|
||||
@@ -1,80 +0,0 @@
|
||||
package container
|
||||
|
||||
import "core:mem"
|
||||
|
||||
Bloom_Hash_Proc :: #type proc(data: []byte) -> u32
|
||||
|
||||
Bloom_Hash :: struct {
|
||||
hash_proc: Bloom_Hash_Proc,
|
||||
next: ^Bloom_Hash,
|
||||
}
|
||||
|
||||
Bloom_Filter :: struct {
|
||||
allocator: mem.Allocator,
|
||||
hash: ^Bloom_Hash,
|
||||
bits: []byte,
|
||||
}
|
||||
|
||||
bloom_filter_init :: proc(b: ^Bloom_Filter, size: int, allocator := context.allocator) {
|
||||
b.allocator = allocator
|
||||
b.bits = make([]byte, size, allocator)
|
||||
}
|
||||
|
||||
bloom_filter_destroy :: proc(b: ^Bloom_Filter) {
|
||||
context.allocator = b.allocator
|
||||
delete(b.bits)
|
||||
for b.hash != nil {
|
||||
hash := b.hash
|
||||
b.hash = b.hash.next
|
||||
free(hash)
|
||||
}
|
||||
}
|
||||
|
||||
bloom_filter_add_hash_proc :: proc(b: ^Bloom_Filter, hash_proc: Bloom_Hash_Proc) {
|
||||
context.allocator = b.allocator
|
||||
h := new(Bloom_Hash)
|
||||
h.hash_proc = hash_proc
|
||||
|
||||
head := &b.hash
|
||||
for head^ != nil {
|
||||
head = &(head^.next)
|
||||
}
|
||||
head^ = h
|
||||
}
|
||||
|
||||
bloom_filter_add :: proc(b: ^Bloom_Filter, item: []byte) {
|
||||
#no_bounds_check for h := b.hash; h != nil; h = h.next {
|
||||
hash := h.hash_proc(item)
|
||||
hash %= u32(len(b.bits) * 8)
|
||||
b.bits[hash >> 3] |= 1 << (hash & 3)
|
||||
}
|
||||
}
|
||||
|
||||
bloom_filter_add_string :: proc(b: ^Bloom_Filter, item: string) {
|
||||
bloom_filter_add(b, transmute([]byte)item)
|
||||
}
|
||||
|
||||
bloom_filter_add_raw :: proc(b: ^Bloom_Filter, data: rawptr, size: int) {
|
||||
item := mem.slice_ptr((^byte)(data), size)
|
||||
bloom_filter_add(b, item)
|
||||
}
|
||||
|
||||
bloom_filter_test :: proc(b: ^Bloom_Filter, item: []byte) -> bool {
|
||||
#no_bounds_check for h := b.hash; h != nil; h = h.next {
|
||||
hash := h.hash_proc(item)
|
||||
hash %= u32(len(b.bits) * 8)
|
||||
if (b.bits[hash >> 3] & (1 << (hash & 3)) == 0) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
bloom_filter_test_string :: proc(b: ^Bloom_Filter, item: string) -> bool {
|
||||
return bloom_filter_test(b, transmute([]byte)item)
|
||||
}
|
||||
|
||||
bloom_filter_test_raw :: proc(b: ^Bloom_Filter, data: rawptr, size: int) -> bool {
|
||||
item := mem.slice_ptr((^byte)(data), size)
|
||||
return bloom_filter_test(b, item)
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package container_intrusive_list
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
// An intrusive doubly-linked list
|
||||
//
|
||||
// As this is an intrusive container, a `Node` must be embedded in your own
|
||||
// structure which is conventionally called a "link". The use of `push_front`
|
||||
// and `push_back` take the address of this node. Retrieving the data
|
||||
// associated with the node requires finding the relative offset of the node
|
||||
// of the parent structure. The parent type and field name are given to
|
||||
// `iterator_*` procedures, or to the built-in `container_of` procedure.
|
||||
//
|
||||
// This data structure is two-pointers in size:
|
||||
// 8 bytes on 32-bit platforms and 16 bytes on 64-bit platforms
|
||||
List :: struct {
|
||||
head: ^Node,
|
||||
tail: ^Node,
|
||||
}
|
||||
|
||||
|
||||
Node :: struct {
|
||||
next, prev: ^Node,
|
||||
}
|
||||
|
||||
push_front :: proc(list: ^List, node: ^Node) {
|
||||
if list.head != nil {
|
||||
list.head.prev = node
|
||||
node.prev, node.next = nil, list.head
|
||||
list.head = node
|
||||
} else {
|
||||
list.head, list.tail = node, node
|
||||
node.prev, node.next = nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
push_back :: proc(list: ^List, node: ^Node) {
|
||||
if list.tail != nil {
|
||||
list.tail.next = node
|
||||
node.prev, node.next = list.tail, nil
|
||||
list.tail = node
|
||||
} else {
|
||||
list.head, list.tail = node, node
|
||||
node.prev, node.next = nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
remove :: proc(list: ^List, node: ^Node) {
|
||||
if node != nil {
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
}
|
||||
if node.prev != nil {
|
||||
node.prev.next = node.next
|
||||
}
|
||||
if list.head == node {
|
||||
list.head = node.next
|
||||
}
|
||||
if list.tail == node {
|
||||
list.tail = node.prev
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
|
||||
for node := list.head; node != nil; {
|
||||
next := node.next
|
||||
if to_erase(node) {
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
}
|
||||
if node.prev != nil {
|
||||
node.prev.next = node.next
|
||||
}
|
||||
if list.head == node {
|
||||
list.head = node.next
|
||||
}
|
||||
if list.tail == node {
|
||||
list.tail = node.prev
|
||||
}
|
||||
}
|
||||
node = next
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
is_empty :: proc(list: ^List) -> bool {
|
||||
return list.head == nil
|
||||
}
|
||||
|
||||
pop_front :: proc(list: ^List) -> ^Node {
|
||||
link := list.head
|
||||
if link == nil {
|
||||
return nil
|
||||
}
|
||||
if link.next != nil {
|
||||
link.next.prev = link.prev
|
||||
}
|
||||
if link.prev != nil {
|
||||
link.prev.next = link.next
|
||||
}
|
||||
if link == list.head {
|
||||
list.head = link.next
|
||||
}
|
||||
if link == list.tail {
|
||||
list.tail = link.prev
|
||||
}
|
||||
return link
|
||||
|
||||
}
|
||||
pop_back :: proc(list: ^List) -> ^Node {
|
||||
link := list.tail
|
||||
if link == nil {
|
||||
return nil
|
||||
}
|
||||
if link.next != nil {
|
||||
link.next.prev = link.prev
|
||||
}
|
||||
if link.prev != nil {
|
||||
link.prev.next = link.next
|
||||
}
|
||||
if link == list.head {
|
||||
list.head = link.next
|
||||
}
|
||||
if link == list.tail {
|
||||
list.tail = link.prev
|
||||
}
|
||||
return link
|
||||
}
|
||||
|
||||
|
||||
Iterator :: struct($T: typeid) {
|
||||
curr: ^Node,
|
||||
offset: uintptr,
|
||||
}
|
||||
|
||||
iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
where intrinsics.type_has_field(T, field_name),
|
||||
intrinsics.type_field_type(T, field_name) == Node {
|
||||
return {list.head, offset_of_by_string(T, field_name)}
|
||||
}
|
||||
|
||||
iterator_tail :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
where intrinsics.type_has_field(T, field_name),
|
||||
intrinsics.type_field_type(T, field_name) == Node {
|
||||
return {list.tail, offset_of_by_string(T, field_name)}
|
||||
}
|
||||
|
||||
iterator_from_node :: proc(node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
where intrinsics.type_has_field(T, field_name),
|
||||
intrinsics.type_field_type(T, field_name) == Node {
|
||||
return {node, offset_of_by_string(T, field_name)}
|
||||
}
|
||||
|
||||
iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
}
|
||||
it.curr = node.next
|
||||
|
||||
return (^T)(uintptr(node) - it.offset), true
|
||||
}
|
||||
|
||||
iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
}
|
||||
it.curr = node.prev
|
||||
|
||||
return (^T)(uintptr(node) - it.offset), true
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package container_lru
|
||||
|
||||
import "core:runtime"
|
||||
import "core:intrinsics"
|
||||
_ :: runtime
|
||||
_ :: intrinsics
|
||||
|
||||
Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||
prev, next: ^Node(Key, Value),
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
// Cache is an LRU cache. It automatically removes entries as new entries are
|
||||
// added if the capacity is reached. Entries are removed based on how recently
|
||||
// they were used where the oldest entries are removed first.
|
||||
Cache :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||
head: ^Node(Key, Value),
|
||||
tail: ^Node(Key, Value),
|
||||
|
||||
entries: map[Key]^Node(Key, Value),
|
||||
|
||||
count: int,
|
||||
capacity: int,
|
||||
|
||||
node_allocator: runtime.Allocator,
|
||||
|
||||
on_remove: proc(key: Key, value: Value, user_data: rawptr),
|
||||
on_remove_user_data: rawptr,
|
||||
}
|
||||
|
||||
// init initializes a Cache
|
||||
init :: proc(c: ^$C/Cache($Key, $Value), capacity: int, entries_allocator := context.allocator, node_allocator := context.allocator) {
|
||||
c.entries.allocator = entries_allocator
|
||||
c.node_allocator = node_allocator
|
||||
c.capacity = capacity
|
||||
}
|
||||
|
||||
// destroy deinitializes a Cachem
|
||||
destroy :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
|
||||
clear(c, call_on_remove)
|
||||
delete(c.entries)
|
||||
}
|
||||
|
||||
// clear the contents of a Cache
|
||||
clear :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
|
||||
for _, node in c.entries {
|
||||
if call_on_remove {
|
||||
_call_on_remove(c, node)
|
||||
}
|
||||
free(node, c.node_allocator)
|
||||
}
|
||||
runtime.clear(&c.entries)
|
||||
c.head = nil
|
||||
c.tail = nil
|
||||
c.count = 0
|
||||
}
|
||||
|
||||
// set the given key value pair. This operation updates the recent usage of the item.
|
||||
set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Allocator_Error {
|
||||
if e, ok := c.entries[key]; ok {
|
||||
e.value = value
|
||||
_pop_node(c, e)
|
||||
_push_front_node(c, e)
|
||||
return nil
|
||||
}
|
||||
|
||||
e : ^Node(Key, Value) = nil
|
||||
assert(c.count <= c.capacity)
|
||||
if c.count == c.capacity {
|
||||
e = c.tail
|
||||
_remove_node(c, e)
|
||||
}
|
||||
else {
|
||||
c.count += 1
|
||||
e = new(Node(Key, Value), c.node_allocator) or_return
|
||||
}
|
||||
|
||||
e.key = key
|
||||
e.value = value
|
||||
_push_front_node(c, e)
|
||||
c.entries[key] = e
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// get a value from the cache from a given key. This operation updates the usage of the item.
|
||||
get :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
|
||||
e: ^Node(Key, Value)
|
||||
e, ok = c.entries[key]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
_pop_node(c, e)
|
||||
_push_front_node(c, e)
|
||||
return e.value, true
|
||||
}
|
||||
|
||||
// get_ptr gets the pointer to a value the cache from a given key. This operation updates the usage of the item.
|
||||
get_ptr :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: ^Value, ok: bool) #optional_ok {
|
||||
e: ^Node(Key, Value)
|
||||
e, ok = c.entries[key]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
_pop_node(c, e)
|
||||
_push_front_node(c, e)
|
||||
return &e.value, true
|
||||
}
|
||||
|
||||
// peek gets the value from the cache from a given key without updating the recent usage.
|
||||
peek :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
|
||||
e: ^Node(Key, Value)
|
||||
e, ok = c.entries[key]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
return e.value, true
|
||||
}
|
||||
|
||||
// exists checks for the existence of a value from a given key without updating the recent usage.
|
||||
exists :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
|
||||
return key in c.entries
|
||||
}
|
||||
|
||||
// remove removes an item from the cache.
|
||||
remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
|
||||
e, ok := c.entries[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_remove_node(c, e)
|
||||
free(node, c.node_allocator)
|
||||
c.count -= 1
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
_remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
|
||||
if c.head == node {
|
||||
c.head = node.next
|
||||
}
|
||||
if c.tail == node {
|
||||
c.tail = node.prev
|
||||
}
|
||||
if node.prev != nil {
|
||||
node.prev.next = node.next
|
||||
}
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
}
|
||||
node.prev = nil
|
||||
node.next = nil
|
||||
|
||||
delete_key(&c.entries, node.key)
|
||||
|
||||
_call_on_remove(c, node)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_call_on_remove :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
|
||||
if c.on_remove != nil {
|
||||
c.on_remove(node.key, node.value, c.on_remove_user_data)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
||||
if c.head != nil {
|
||||
e.next = c.head
|
||||
e.next.prev = e
|
||||
}
|
||||
c.head = e
|
||||
if c.tail == nil {
|
||||
c.tail = e
|
||||
}
|
||||
e.prev = nil
|
||||
}
|
||||
|
||||
@(private)
|
||||
_pop_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
if c.head == e {
|
||||
c.head = e.next
|
||||
}
|
||||
if c.tail == e {
|
||||
c.tail = e.prev
|
||||
}
|
||||
if e.prev != nil {
|
||||
e.prev.next = e.next
|
||||
}
|
||||
|
||||
if e.next != nil {
|
||||
e.next.prev = e.prev
|
||||
}
|
||||
e.prev = nil
|
||||
e.next = nil
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
package container
|
||||
|
||||
import "core:intrinsics"
|
||||
_ :: intrinsics
|
||||
|
||||
|
||||
Map :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||
hash: Array(int),
|
||||
entries: Array(Map_Entry(Key, Value)),
|
||||
}
|
||||
|
||||
Map_Entry :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
map_init :: proc{
|
||||
map_init_none,
|
||||
map_init_cap,
|
||||
}
|
||||
map_delete
|
||||
|
||||
map_has
|
||||
map_get
|
||||
map_get_default
|
||||
map_get_ptr
|
||||
map_set
|
||||
map_remove
|
||||
map_reserve
|
||||
map_clear
|
||||
|
||||
// Multi Map
|
||||
|
||||
multi_map_find_first
|
||||
multi_map_find_next
|
||||
multi_map_count
|
||||
multi_map_get :: proc{
|
||||
multi_map_get_array,
|
||||
multi_map_get_slice,
|
||||
};
|
||||
multi_map_get_as_slice
|
||||
multi_map_insert
|
||||
multi_map_remove
|
||||
multi_map_remove_all
|
||||
|
||||
*/
|
||||
|
||||
map_init :: proc{map_init_none, map_init_cap}
|
||||
|
||||
map_init_none :: proc(m: ^$M/Map($Key, $Value), allocator := context.allocator) {
|
||||
m.hash.allocator = allocator
|
||||
m.entries.allocator = allocator
|
||||
}
|
||||
|
||||
map_init_cap :: proc(m: ^$M/Map($Key, $Value), cap: int, allocator := context.allocator) {
|
||||
m.hash.allocator = allocator
|
||||
m.entries.allocator = allocator
|
||||
map_reserve(m, cap)
|
||||
}
|
||||
|
||||
map_delete :: proc(m: $M/Map($Key, $Value)) {
|
||||
array_delete(m.hash)
|
||||
array_delete(m.entries)
|
||||
}
|
||||
|
||||
|
||||
map_has :: proc(m: $M/Map($Key, $Value), key: Key) -> bool {
|
||||
return _map_find_or_fail(m, key) >= 0
|
||||
}
|
||||
|
||||
map_get :: proc(m: $M/Map($Key, $Value), key: Key) -> (res: Value, ok: bool) #optional_ok {
|
||||
i := _map_find_or_fail(m, key)
|
||||
if i < 0 {
|
||||
return {}, false
|
||||
}
|
||||
return array_get(m.entries, i).value, true
|
||||
}
|
||||
|
||||
map_get_default :: proc(m: $M/Map($Key, $Value), key: Key, default: Value) -> (res: Value, ok: bool) #optional_ok {
|
||||
i := _map_find_or_fail(m, key)
|
||||
if i < 0 {
|
||||
return default, false
|
||||
}
|
||||
return array_get(m.entries, i).value, true
|
||||
}
|
||||
|
||||
map_get_ptr :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Value {
|
||||
i := _map_find_or_fail(m, key)
|
||||
if i < 0 {
|
||||
return nil
|
||||
}
|
||||
return array_get_ptr(m.entries, i).value
|
||||
}
|
||||
|
||||
map_set :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) {
|
||||
if array_len(m.hash) == 0 {
|
||||
_map_grow(m)
|
||||
}
|
||||
|
||||
i := _map_find_or_make(m, key)
|
||||
array_get_ptr(m.entries, i).value = value
|
||||
if _map_full(m^) {
|
||||
_map_grow(m)
|
||||
}
|
||||
}
|
||||
|
||||
map_remove :: proc(m: ^$M/Map($Key, $Value), key: Key) {
|
||||
fr := _map_find_key(m^, key)
|
||||
if fr.entry_index >= 0 {
|
||||
_map_erase(m, fr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
map_reserve :: proc(m: ^$M/Map($Key, $Value), new_size: int) {
|
||||
nm: M
|
||||
map_init(&nm, m.hash.allocator)
|
||||
array_resize(&nm.hash, new_size)
|
||||
array_reserve(&nm.entries, array_len(m.entries))
|
||||
|
||||
for i in 0..<new_size {
|
||||
array_set(&nm.hash, i, -1)
|
||||
}
|
||||
for i in 0..<array_len(m.entries) {
|
||||
e := array_get(m.entries, i)
|
||||
multi_map_insert(&nm, e.key, e.value)
|
||||
}
|
||||
|
||||
map_delete(m^)
|
||||
m^ = nm
|
||||
}
|
||||
|
||||
map_clear :: proc(m: ^$M/Map($Key, $Value)) {
|
||||
array_clear(&m.hash)
|
||||
array_clear(&m.entries)
|
||||
}
|
||||
|
||||
|
||||
|
||||
multi_map_find_first :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Map_Entry(Key, Value) {
|
||||
i := _map_find_or_fail(m, key)
|
||||
if i < 0 {
|
||||
return nil
|
||||
}
|
||||
return array_get_ptr(m.entries, i)
|
||||
}
|
||||
|
||||
multi_map_find_next :: proc(m: $M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) -> ^Map_Entry(Key, Value) {
|
||||
i := e.next
|
||||
for i >= 0 {
|
||||
it := array_get_ptr(m.entries, i)
|
||||
if it.hash == e.hash && it.key == e.key {
|
||||
return it
|
||||
}
|
||||
i = it.next
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
multi_map_count :: proc(m: $M/Map($Key, $Value), key: Key) -> int {
|
||||
n := 0
|
||||
e := multi_map_find_first(m, key)
|
||||
for e != nil {
|
||||
n += 1
|
||||
e = multi_map_find_next(m, e)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
multi_map_get :: proc{multi_map_get_array, multi_map_get_slice}
|
||||
|
||||
multi_map_get_array :: proc(m: $M/Map($Key, $Value), key: Key, items: ^Array(Value)) {
|
||||
if items == nil {
|
||||
return
|
||||
}
|
||||
e := multi_map_find_first(m, key)
|
||||
for e != nil {
|
||||
array_append(items, e.value)
|
||||
e = multi_map_find_next(m, e)
|
||||
}
|
||||
}
|
||||
|
||||
multi_map_get_slice :: proc(m: $M/Map($Key, $Value), key: Key, items: []Value) {
|
||||
e := multi_map_find_first(m, key)
|
||||
i := 0
|
||||
for e != nil && i < len(items) {
|
||||
items[i] = e.value
|
||||
i += 1
|
||||
e = multi_map_find_next(m, e)
|
||||
}
|
||||
}
|
||||
|
||||
multi_map_get_as_slice :: proc(m: $M/Map($Key, $Value), key: Key) -> []Value {
|
||||
items: Array(Value)
|
||||
array_init(&items, 0)
|
||||
|
||||
e := multi_map_find_first(m, key)
|
||||
for e != nil {
|
||||
array_append(&items, e.value)
|
||||
e = multi_map_find_next(m, e)
|
||||
}
|
||||
|
||||
return array_slice(items)
|
||||
}
|
||||
|
||||
|
||||
multi_map_insert :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) {
|
||||
if array_len(m.hash) == 0 {
|
||||
_map_grow(m)
|
||||
}
|
||||
|
||||
i := _map_make(m, key)
|
||||
array_get_ptr(m.entries, i).value = value
|
||||
if _map_full(m^) {
|
||||
_map_grow(m)
|
||||
}
|
||||
}
|
||||
|
||||
multi_map_remove :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) {
|
||||
fr := _map_find_entry(m, e)
|
||||
if fr.entry_index >= 0 {
|
||||
_map_erase(m, fr)
|
||||
}
|
||||
}
|
||||
|
||||
multi_map_remove_all :: proc(m: ^$M/Map($Key, $Value), key: Key) {
|
||||
for map_exist(m^, key) {
|
||||
map_remove(m, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Internal
|
||||
|
||||
|
||||
Map_Find_Result :: struct {
|
||||
hash_index: int,
|
||||
entry_prev: int,
|
||||
entry_index: int,
|
||||
}
|
||||
|
||||
_map_add_entry :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int where intrinsics.type_is_valid_map_key(Key) {
|
||||
hasher := intrinsics.type_hasher_proc(Key)
|
||||
|
||||
e: Map_Entry(Key, Value)
|
||||
e.key = key
|
||||
e.hash = hasher(&e.key, 0)
|
||||
e.next = -1
|
||||
idx := array_len(m.entries)
|
||||
array_push(&m.entries, e)
|
||||
return idx
|
||||
}
|
||||
|
||||
_map_erase :: proc(m: ^$M/Map, fr: Map_Find_Result) {
|
||||
if fr.entry_prev < 0 {
|
||||
array_set(&m.hash, fr.hash_index, array_get(m.entries, fr.entry_index).next)
|
||||
} else {
|
||||
array_get_ptr(m.entries, fr.entry_prev).next = array_get(m.entries, fr.entry_index).next
|
||||
}
|
||||
|
||||
if fr.entry_index == array_len(m.entries)-1 {
|
||||
array_pop_back(&m.entries)
|
||||
return
|
||||
}
|
||||
|
||||
array_set(&m.entries, fr.entry_index, array_get(m.entries, array_len(m.entries)-1))
|
||||
last := _map_find_key(m^, array_get(m.entries, fr.entry_index).key)
|
||||
|
||||
if last.entry_prev < 0 {
|
||||
array_get_ptr(m.entries, last.entry_prev).next = fr.entry_index
|
||||
} else {
|
||||
array_set(&m.hash, last.hash_index, fr.entry_index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_map_find_key :: proc(m: $M/Map($Key, $Value), key: Key) -> Map_Find_Result where intrinsics.type_is_valid_map_key(Key) {
|
||||
fr: Map_Find_Result
|
||||
fr.hash_index = -1
|
||||
fr.entry_prev = -1
|
||||
fr.entry_index = -1
|
||||
|
||||
if array_len(m.hash) == 0 {
|
||||
return fr
|
||||
}
|
||||
|
||||
hasher := intrinsics.type_hasher_proc(Key)
|
||||
|
||||
key := key
|
||||
hash := hasher(&key, 0)
|
||||
|
||||
fr.hash_index = int(hash % uintptr(array_len(m.hash)))
|
||||
fr.entry_index = array_get(m.hash, fr.hash_index)
|
||||
for fr.entry_index >= 0 {
|
||||
it := array_get_ptr(m.entries, fr.entry_index)
|
||||
if it.hash == hash && it.key == key {
|
||||
return fr
|
||||
}
|
||||
fr.entry_prev = fr.entry_index
|
||||
fr.entry_index = it.next
|
||||
}
|
||||
return fr
|
||||
}
|
||||
|
||||
_map_find_entry :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) -> Map_Find_Result {
|
||||
fr: Map_Find_Result
|
||||
fr.hash_index = -1
|
||||
fr.entry_prev = -1
|
||||
fr.entry_index = -1
|
||||
|
||||
if array_len(m.hash) == 0 {
|
||||
return fr
|
||||
}
|
||||
|
||||
fr.hash_index = int(e.hash % uintptr(array_len(m.hash)))
|
||||
fr.entry_index = array_get(m.hash, fr.hash_index)
|
||||
for fr.entry_index >= 0 {
|
||||
it := array_get_ptr(m.entries, fr.entry_index)
|
||||
if it == e {
|
||||
return fr
|
||||
}
|
||||
fr.entry_prev = fr.entry_index
|
||||
fr.entry_index = it.next
|
||||
}
|
||||
return fr
|
||||
}
|
||||
|
||||
_map_find_or_fail :: proc(m: $M/Map($Key, $Value), key: Key) -> int {
|
||||
return _map_find_key(m, key).entry_index
|
||||
}
|
||||
_map_find_or_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int {
|
||||
fr := _map_find_key(m^, key)
|
||||
if fr.entry_index >= 0 {
|
||||
return fr.entry_index
|
||||
}
|
||||
|
||||
i := _map_add_entry(m, key)
|
||||
if fr.entry_prev < 0 {
|
||||
array_set(&m.hash, fr.hash_index, i)
|
||||
} else {
|
||||
array_get_ptr(m.entries, fr.entry_prev).next = i
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
_map_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int {
|
||||
fr := _map_find_key(m^, key)
|
||||
i := _map_add_entry(m, key)
|
||||
|
||||
if fr.entry_prev < 0 {
|
||||
array_set(&m.hash, fr.hash_index, i)
|
||||
} else {
|
||||
array_get_ptr(m.entries, fr.entry_prev).next = i
|
||||
}
|
||||
|
||||
array_get_ptr(m.entries, i).next = fr.entry_index
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
_map_full :: proc(m: $M/Map($Key, $Value)) -> bool {
|
||||
// TODO(bill): Determine good max load factor
|
||||
return array_len(m.entries) >= (array_len(m.hash) / 4)*3
|
||||
}
|
||||
|
||||
_map_grow :: proc(m: ^$M/Map($Key, $Value)) {
|
||||
new_size := array_len(m.entries) * 4 + 7 // TODO(bill): Determine good grow rate
|
||||
map_reserve(m, new_size)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
package container
|
||||
|
||||
Priority_Queue :: struct($T: typeid) {
|
||||
data: Array(T),
|
||||
len: int,
|
||||
priority: proc(item: T) -> int,
|
||||
}
|
||||
|
||||
priority_queue_init_none :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, allocator := context.allocator) {
|
||||
queue_init_len(q, f, 0, allocator)
|
||||
}
|
||||
priority_queue_init_len :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, allocator := context.allocator) {
|
||||
queue_init_len_cap(q, f, 0, 16, allocator)
|
||||
}
|
||||
priority_queue_init_len_cap :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, cap: int, allocator := context.allocator) {
|
||||
array_init(&q.data, len, cap, allocator)
|
||||
q.len = len
|
||||
q.priority = f
|
||||
}
|
||||
|
||||
priority_queue_init :: proc{priority_queue_init_none, priority_queue_init_len, priority_queue_init_len_cap}
|
||||
|
||||
|
||||
priority_queue_delete :: proc(q: $Q/Priority_Queue($T)) {
|
||||
array_delete(q.data)
|
||||
}
|
||||
|
||||
priority_queue_clear :: proc(q: ^$Q/Priority_Queue($T)) {
|
||||
q.len = 0
|
||||
}
|
||||
|
||||
priority_queue_len :: proc(q: $Q/Priority_Queue($T)) -> int {
|
||||
return q.len
|
||||
}
|
||||
|
||||
priority_queue_cap :: proc(q: $Q/Priority_Queue($T)) -> int {
|
||||
return array_cap(q.data)
|
||||
}
|
||||
|
||||
priority_queue_space :: proc(q: $Q/Priority_Queue($T)) -> int {
|
||||
return array_len(q.data) - q.len
|
||||
}
|
||||
|
||||
priority_queue_reserve :: proc(q: ^$Q/Priority_Queue($T), capacity: int) {
|
||||
if capacity > q.len {
|
||||
array_resize(&q.data, new_capacity)
|
||||
}
|
||||
}
|
||||
|
||||
priority_queue_resize :: proc(q: ^$Q/Priority_Queue($T), length: int) {
|
||||
if length > q.len {
|
||||
array_resize(&q.data, new_capacity)
|
||||
}
|
||||
q.len = length
|
||||
}
|
||||
|
||||
_priority_queue_grow :: proc(q: ^$Q/Priority_Queue($T), min_capacity: int = 0) {
|
||||
new_capacity := max(array_len(q.data)*2 + 8, min_capacity)
|
||||
array_resize(&q.data, new_capacity)
|
||||
}
|
||||
|
||||
|
||||
priority_queue_push :: proc(q: ^$Q/Priority_Queue($T), item: T) {
|
||||
if array_len(q.data) - q.len == 0 {
|
||||
_priority_queue_grow(q)
|
||||
}
|
||||
|
||||
s := array_slice(q.data)
|
||||
s[q.len] = item
|
||||
|
||||
i := q.len
|
||||
for i > 0 {
|
||||
p := (i - 1) / 2
|
||||
if q.priority(s[p]) <= q.priority(item) {
|
||||
break
|
||||
}
|
||||
s[i] = s[p]
|
||||
i = p
|
||||
}
|
||||
|
||||
q.len += 1
|
||||
if q.len > 0 {
|
||||
s[i] = item
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
priority_queue_pop :: proc(q: ^$Q/Priority_Queue($T)) -> T {
|
||||
assert(q.len > 0)
|
||||
|
||||
s := array_slice(q.data)
|
||||
min := s[0]
|
||||
root := s[q.len-1]
|
||||
q.len -= 1
|
||||
|
||||
i := 0
|
||||
for i * 2 + 1 < q.len {
|
||||
a := i * 2 + 1
|
||||
b := i * 2 + 2
|
||||
c := b < q.len && q.priority(s[b]) < q.priority(s[a]) ? b : a
|
||||
|
||||
if q.priority(s[c]) >= q.priority(root) {
|
||||
break
|
||||
}
|
||||
s[i] = s[c]
|
||||
i = c
|
||||
}
|
||||
|
||||
if q.len > 0 {
|
||||
s[i] = root
|
||||
}
|
||||
return min
|
||||
}
|
||||
|
||||
priority_queue_peek :: proc(q: ^$Q/Priority_Queue($T)) -> T {
|
||||
assert(q.len > 0)
|
||||
|
||||
s := array_slice(q.data)
|
||||
return s[0]
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package container_priority_queue
|
||||
|
||||
import "core:builtin"
|
||||
|
||||
Priority_Queue :: struct($T: typeid) {
|
||||
queue: [dynamic]T,
|
||||
|
||||
less: proc(a, b: T) -> bool,
|
||||
swap: proc(q: []T, i, j: int),
|
||||
}
|
||||
|
||||
DEFAULT_CAPACITY :: 16
|
||||
|
||||
default_swap_proc :: proc($T: typeid) -> proc(q: []T, i, j: int) {
|
||||
return proc(q: []T, i, j: int) {
|
||||
q[i], q[j] = q[j], q[i]
|
||||
}
|
||||
}
|
||||
|
||||
init :: proc(pq: ^$Q/Priority_Queue($T), less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int), capacity := DEFAULT_CAPACITY, allocator := context.allocator) {
|
||||
if pq.queue.allocator.procedure == nil {
|
||||
pq.queue.allocator = allocator
|
||||
}
|
||||
reserve(pq, capacity)
|
||||
pq.less = less
|
||||
pq.swap = swap
|
||||
}
|
||||
|
||||
init_from_dynamic_array :: proc(pq: ^$Q/Priority_Queue($T), queue: [dynamic]T, less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int)) {
|
||||
pq.queue = queue
|
||||
pq.less = less
|
||||
pq.swap = swap
|
||||
n := builtin.len(pq.queue)
|
||||
for i := n/2 - 1; i >= 0; i -= 1 {
|
||||
_shift_down(pq, i, n)
|
||||
}
|
||||
}
|
||||
|
||||
destroy :: proc(pq: ^$Q/Priority_Queue($T)) {
|
||||
clear(pq)
|
||||
delete(pq.queue)
|
||||
}
|
||||
|
||||
reserve :: proc(pq: ^$Q/Priority_Queue($T), capacity: int) {
|
||||
builtin.reserve(&pq.queue, capacity)
|
||||
}
|
||||
clear :: proc(pq: ^$Q/Priority_Queue($T)) {
|
||||
builtin.clear(&pq.queue)
|
||||
}
|
||||
len :: proc(pq: $Q/Priority_Queue($T)) -> int {
|
||||
return builtin.len(pq.queue)
|
||||
}
|
||||
cap :: proc(pq: $Q/Priority_Queue($T)) -> int {
|
||||
return builtin.cap(pq.queue)
|
||||
}
|
||||
|
||||
_shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool {
|
||||
// O(n log n)
|
||||
if 0 > i0 || i0 > n {
|
||||
return false
|
||||
}
|
||||
|
||||
i := i0
|
||||
queue := pq.queue[:]
|
||||
|
||||
for {
|
||||
j1 := 2*i + 1
|
||||
if j1 < 0 || j1 >= n {
|
||||
break
|
||||
}
|
||||
j := j1
|
||||
if j2 := j1+1; j2 < n && pq.less(queue[j2], queue[j1]) {
|
||||
j = j2
|
||||
}
|
||||
if !pq.less(queue[j], queue[i]) {
|
||||
break
|
||||
}
|
||||
|
||||
pq.swap(queue, i, j)
|
||||
i = j
|
||||
}
|
||||
return i > i0
|
||||
}
|
||||
|
||||
_shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) {
|
||||
j := j
|
||||
queue := pq.queue[:]
|
||||
n := builtin.len(queue)
|
||||
for 0 <= j {
|
||||
i := (j-1)/2
|
||||
if i == j || !pq.less(queue[j], queue[i]) {
|
||||
break
|
||||
}
|
||||
pq.swap(queue, i, j)
|
||||
j = i
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): When an element at index 'i' has changed its value, this will fix the
|
||||
// the heap ordering. This is using a basic "heapsort" with shift up and a shift down parts.
|
||||
fix :: proc(pq: ^$Q/Priority_Queue($T), i: int) {
|
||||
if !_shift_down(pq, i, builtin.len(pq.queue)) {
|
||||
_shift_up(pq, i)
|
||||
}
|
||||
}
|
||||
|
||||
push :: proc(pq: ^$Q/Priority_Queue($T), value: T) {
|
||||
append(&pq.queue, value)
|
||||
_shift_up(pq, builtin.len(pq.queue)-1)
|
||||
}
|
||||
|
||||
pop :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: T) {
|
||||
assert(condition=builtin.len(pq.queue)>0, loc=loc)
|
||||
|
||||
n := builtin.len(pq.queue)-1
|
||||
pq.swap(pq.queue[:], 0, n)
|
||||
_shift_down(pq, 0, n)
|
||||
return builtin.pop(&pq.queue)
|
||||
}
|
||||
|
||||
pop_safe :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: T, ok: bool) {
|
||||
if builtin.len(pq.queue) > 0 {
|
||||
n := builtin.len(pq.queue)-1
|
||||
pq.swap(pq.queue[:], 0, n)
|
||||
_shift_down(pq, 0, n)
|
||||
return builtin.pop_safe(&pq.queue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
remove :: proc(pq: ^$Q/Priority_Queue($T), i: int) -> (value: T, ok: bool) {
|
||||
n := builtin.len(pq.queue)
|
||||
if 0 <= i && i < n {
|
||||
if n != i {
|
||||
pq.swap(pq.queue[:], i, n)
|
||||
_shift_down(pq, i, n)
|
||||
_shift_up(pq, i)
|
||||
}
|
||||
value, ok = builtin.pop_safe(&pq.queue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
package container
|
||||
|
||||
Queue :: struct($T: typeid) {
|
||||
data: Array(T),
|
||||
len: int,
|
||||
offset: int,
|
||||
}
|
||||
|
||||
/*
|
||||
queue_init :: proc{
|
||||
queue_init_none,
|
||||
queue_init_len,
|
||||
queue_init_len_cap,
|
||||
}
|
||||
queue_delete
|
||||
queue_clear
|
||||
queue_len
|
||||
queue_cap
|
||||
queue_space
|
||||
queue_get
|
||||
queue_set
|
||||
queue_reserve
|
||||
queue_resize
|
||||
queue_push :: proc{
|
||||
queue_push_back,
|
||||
queue_push_elems,
|
||||
};
|
||||
queue_push_front
|
||||
queue_pop_front
|
||||
queue_pop_back
|
||||
queue_consume
|
||||
*/
|
||||
|
||||
queue_init_none :: proc(q: ^$Q/Queue($T), allocator := context.allocator) {
|
||||
queue_init_len(q, 0, allocator)
|
||||
}
|
||||
queue_init_len :: proc(q: ^$Q/Queue($T), len: int, allocator := context.allocator) {
|
||||
queue_init_len_cap(q, 0, 16, allocator)
|
||||
}
|
||||
queue_init_len_cap :: proc(q: ^$Q/Queue($T), len: int, cap: int, allocator := context.allocator) {
|
||||
array_init(&q.data, len, cap, allocator)
|
||||
q.len = len
|
||||
q.offset = 0
|
||||
}
|
||||
|
||||
queue_init :: proc{queue_init_none, queue_init_len, queue_init_len_cap}
|
||||
|
||||
queue_delete :: proc(q: $Q/Queue($T)) {
|
||||
array_delete(q.data)
|
||||
}
|
||||
|
||||
queue_clear :: proc(q: ^$Q/Queue($T)) {
|
||||
q.len = 0
|
||||
}
|
||||
|
||||
queue_len :: proc(q: $Q/Queue($T)) -> int {
|
||||
return q.len
|
||||
}
|
||||
|
||||
queue_cap :: proc(q: $Q/Queue($T)) -> int {
|
||||
return array_cap(q.data)
|
||||
}
|
||||
|
||||
queue_space :: proc(q: $Q/Queue($T)) -> int {
|
||||
return array_len(q.data) - q.len
|
||||
}
|
||||
|
||||
queue_get :: proc(q: $Q/Queue($T), index: int) -> T {
|
||||
i := (index + q.offset) % array_len(q.data)
|
||||
data := array_slice(q.data)
|
||||
return data[i]
|
||||
}
|
||||
|
||||
queue_set :: proc(q: ^$Q/Queue($T), index: int, item: T) {
|
||||
i := (index + q.offset) % array_len(q.data)
|
||||
data := array_slice(q.data)
|
||||
data[i] = item
|
||||
}
|
||||
|
||||
|
||||
queue_reserve :: proc(q: ^$Q/Queue($T), capacity: int) {
|
||||
if capacity > q.len {
|
||||
_queue_increase_capacity(q, capacity)
|
||||
}
|
||||
}
|
||||
|
||||
queue_resize :: proc(q: ^$Q/Queue($T), length: int) {
|
||||
if length > q.len {
|
||||
_queue_increase_capacity(q, length)
|
||||
}
|
||||
q.len = length
|
||||
}
|
||||
|
||||
queue_push_back :: proc(q: ^$Q/Queue($T), item: T) {
|
||||
if queue_space(q^) == 0 {
|
||||
_queue_grow(q)
|
||||
}
|
||||
|
||||
queue_set(q, q.len, item)
|
||||
q.len += 1
|
||||
}
|
||||
|
||||
queue_push_front :: proc(q: ^$Q/Queue($T), item: T) {
|
||||
if queue_space(q^) == 0 {
|
||||
_queue_grow(q)
|
||||
}
|
||||
|
||||
q.offset = (q.offset - 1 + array_len(q.data)) % array_len(q.data)
|
||||
q.len += 1
|
||||
queue_set(q, 0, item)
|
||||
}
|
||||
|
||||
queue_pop_front :: proc(q: ^$Q/Queue($T)) -> T {
|
||||
assert(q.len > 0)
|
||||
item := queue_get(q^, 0)
|
||||
q.offset = (q.offset + 1) % array_len(q.data)
|
||||
q.len -= 1
|
||||
if q.len == 0 {
|
||||
q.offset = 0
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
queue_pop_back :: proc(q: ^$Q/Queue($T)) -> T {
|
||||
assert(q.len > 0)
|
||||
item := queue_get(q^, q.len-1)
|
||||
q.len -= 1
|
||||
return item
|
||||
}
|
||||
|
||||
queue_consume :: proc(q: ^$Q/Queue($T), count: int) {
|
||||
q.offset = (q.offset + count) & array_len(q.data)
|
||||
q.len -= count
|
||||
}
|
||||
|
||||
|
||||
queue_push_elems :: proc(q: ^$Q/Queue($T), items: ..T) {
|
||||
if queue_space(q^) < len(items) {
|
||||
_queue_grow(q, q.len + len(items))
|
||||
}
|
||||
size := array_len(q.data)
|
||||
insert := (q.offset + q.len) % size
|
||||
|
||||
to_insert := len(items)
|
||||
if insert + to_insert > size {
|
||||
to_insert = size - insert
|
||||
}
|
||||
|
||||
the_items := items[:]
|
||||
|
||||
data := array_slice(q.data)
|
||||
|
||||
q.len += copy(data[insert:][:to_insert], the_items)
|
||||
the_items = the_items[to_insert:]
|
||||
q.len += copy(data[:], the_items)
|
||||
}
|
||||
|
||||
queue_push :: proc{queue_push_back, queue_push_elems}
|
||||
|
||||
|
||||
|
||||
_queue_increase_capacity :: proc(q: ^$Q/Queue($T), new_capacity: int) {
|
||||
end := array_len(q.data)
|
||||
array_resize(&q.data, new_capacity)
|
||||
if q.offset + q.len > end {
|
||||
end_items := q.len + end
|
||||
data := array_slice(q.data)
|
||||
copy(data[new_capacity-end_items:][:end_items], data[q.offset:][:end_items])
|
||||
q.offset += new_capacity - end
|
||||
}
|
||||
}
|
||||
_queue_grow :: proc(q: ^$Q/Queue($T), min_capacity: int = 0) {
|
||||
new_capacity := max(array_len(q.data)*2 + 8, min_capacity)
|
||||
_queue_increase_capacity(q, new_capacity)
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package container_queue
|
||||
|
||||
import "core:builtin"
|
||||
import "core:runtime"
|
||||
_ :: runtime
|
||||
|
||||
// Dynamically resizable double-ended queue/ring-buffer
|
||||
Queue :: struct($T: typeid) {
|
||||
data: [dynamic]T,
|
||||
len: uint,
|
||||
offset: uint,
|
||||
}
|
||||
|
||||
DEFAULT_CAPACITY :: 16
|
||||
|
||||
// Procedure to initialize a queue
|
||||
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool {
|
||||
if q.data.allocator.procedure == nil {
|
||||
q.data.allocator = allocator
|
||||
}
|
||||
clear(q)
|
||||
return reserve(q, capacity)
|
||||
}
|
||||
|
||||
// Procedure to initialize a queue from a fixed backing slice
|
||||
init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
|
||||
clear(q)
|
||||
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
|
||||
data = raw_data(backing),
|
||||
len = builtin.len(backing),
|
||||
cap = builtin.len(backing),
|
||||
allocator = {procedure=runtime.nil_allocator_proc, data=nil},
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Procedure to destroy a queue
|
||||
destroy :: proc(q: ^$Q/Queue($T)) {
|
||||
delete(q.data)
|
||||
}
|
||||
|
||||
// The length of the queue
|
||||
len :: proc(q: $Q/Queue($T)) -> int {
|
||||
return int(q.len)
|
||||
}
|
||||
|
||||
// The current capacity of the queue
|
||||
cap :: proc(q: $Q/Queue($T)) -> int {
|
||||
return builtin.len(q.data)
|
||||
}
|
||||
|
||||
// Remaining space in the queue (cap-len)
|
||||
space :: proc(q: $Q/Queue($T)) -> int {
|
||||
return builtin.len(q.data) - int(q.len)
|
||||
}
|
||||
|
||||
// Reserve enough space for at least the specified capacity
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool {
|
||||
if uint(capacity) > q.len {
|
||||
return _grow(q, uint(capacity))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T {
|
||||
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
|
||||
|
||||
idx := (uint(i)+q.offset)%builtin.len(q.data)
|
||||
return q.data[idx]
|
||||
}
|
||||
|
||||
front :: proc(q: ^$Q/Queue($T)) -> T {
|
||||
return q.data[q.offset]
|
||||
}
|
||||
|
||||
back :: proc(q: ^$Q/Queue($T)) -> T {
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
return q.data[idx]
|
||||
}
|
||||
|
||||
set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) {
|
||||
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
|
||||
|
||||
idx := (uint(i)+q.offset)%builtin.len(q.data)
|
||||
q.data[idx] = val
|
||||
}
|
||||
get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^T {
|
||||
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
|
||||
|
||||
idx := (uint(i)+q.offset)%builtin.len(q.data)
|
||||
return &q.data[idx]
|
||||
}
|
||||
|
||||
// Push an element to the back of the queue
|
||||
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
||||
if space(q^) == 0 {
|
||||
_grow(q) or_return
|
||||
}
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
q.data[idx] = elem
|
||||
q.len += 1
|
||||
return true
|
||||
}
|
||||
|
||||
// Push an element to the front of the queue
|
||||
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
||||
if space(q^) == 0 {
|
||||
_grow(q) or_return
|
||||
}
|
||||
q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
|
||||
q.len += 1
|
||||
q.data[q.offset] = elem
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// Pop an element from the back of the queue
|
||||
pop_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
|
||||
assert(condition=q.len > 0, loc=loc)
|
||||
q.len -= 1
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
elem = q.data[idx]
|
||||
return
|
||||
}
|
||||
// Safely pop an element from the back of the queue
|
||||
pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
||||
if q.len > 0 {
|
||||
q.len -= 1
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
elem = q.data[idx]
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Pop an element from the front of the queue
|
||||
pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
|
||||
assert(condition=q.len > 0, loc=loc)
|
||||
elem = q.data[q.offset]
|
||||
q.offset = (q.offset+1)%builtin.len(q.data)
|
||||
q.len -= 1
|
||||
return
|
||||
}
|
||||
// Safely pop an element from the front of the queue
|
||||
pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
||||
if q.len > 0 {
|
||||
elem = q.data[q.offset]
|
||||
q.offset = (q.offset+1)%builtin.len(q.data)
|
||||
q.len -= 1
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Push multiple elements to the front of the queue
|
||||
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
|
||||
n := uint(builtin.len(elems))
|
||||
if space(q^) < int(n) {
|
||||
_grow(q, q.len + n) or_return
|
||||
}
|
||||
|
||||
sz := uint(builtin.len(q.data))
|
||||
insert_from := (q.offset + q.len) % sz
|
||||
insert_to := n
|
||||
if insert_from + insert_to > sz {
|
||||
insert_to = sz - insert_from
|
||||
}
|
||||
copy(q.data[insert_from:], elems[:insert_to])
|
||||
copy(q.data[:insert_from], elems[insert_to:])
|
||||
q.len += n
|
||||
return true
|
||||
}
|
||||
|
||||
// Consume `n` elements from the front of the queue
|
||||
consume_front :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) {
|
||||
assert(condition=int(q.len) >= n, loc=loc)
|
||||
if n > 0 {
|
||||
nu := uint(n)
|
||||
q.offset = (q.offset + nu) % builtin.len(q.data)
|
||||
q.len -= nu
|
||||
}
|
||||
}
|
||||
|
||||
// Consume `n` elements from the back of the queue
|
||||
consume_back :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) {
|
||||
assert(condition=int(q.len) >= n, loc=loc)
|
||||
if n > 0 {
|
||||
q.len -= uint(n)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
append_elem :: push_back
|
||||
append_elems :: push_back_elems
|
||||
push :: proc{push_back, push_back_elems}
|
||||
append :: proc{push_back, push_back_elems}
|
||||
|
||||
|
||||
// Clear the contents of the queue
|
||||
clear :: proc(q: ^$Q/Queue($T)) {
|
||||
q.len = 0
|
||||
q.offset = 0
|
||||
}
|
||||
|
||||
|
||||
// Internal growinh procedure
|
||||
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
|
||||
new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
|
||||
n := uint(builtin.len(q.data))
|
||||
builtin.resize(&q.data, int(new_capacity)) or_return
|
||||
if q.offset + q.len > n {
|
||||
diff := n - q.offset
|
||||
copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
|
||||
q.offset += new_capacity - n
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package container
|
||||
|
||||
|
||||
Ring :: struct($T: typeid) {
|
||||
next, prev: ^Ring(T),
|
||||
value: T,
|
||||
}
|
||||
|
||||
ring_init :: proc(r: ^$R/Ring) -> ^R {
|
||||
r.prev, r.next = r, r
|
||||
return r
|
||||
}
|
||||
|
||||
ring_next :: proc(r: ^$R/Ring) -> ^R {
|
||||
if r.next == nil {
|
||||
return ring_init(r)
|
||||
}
|
||||
return r.next
|
||||
}
|
||||
ring_prev :: proc(r: ^$R/Ring) -> ^R {
|
||||
if r.prev == nil {
|
||||
return ring_init(r)
|
||||
}
|
||||
return r.prev
|
||||
}
|
||||
|
||||
|
||||
ring_move :: proc(r: ^$R/Ring, n: int) -> ^R {
|
||||
r := r
|
||||
if r.next == nil {
|
||||
return ring_init(r)
|
||||
}
|
||||
|
||||
switch {
|
||||
case n < 0:
|
||||
for _ in n..<0 {
|
||||
r = r.prev
|
||||
}
|
||||
case n > 0:
|
||||
for _ in 0..<n {
|
||||
r = r.next
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
ring_link :: proc(r, s: ^$R/Ring) -> ^R {
|
||||
n := ring_next(r)
|
||||
if s != nil {
|
||||
p := ring_prev(s)
|
||||
r.next = s
|
||||
s.prev = r
|
||||
n.prev = p
|
||||
p.next = n
|
||||
}
|
||||
return n
|
||||
}
|
||||
ring_unlink :: proc(r: ^$R/Ring, n: int) -> ^R {
|
||||
if n <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ring_link(r, ring_move(r, n+1))
|
||||
}
|
||||
ring_len :: proc(r: ^$R/Ring) -> int {
|
||||
n := 0
|
||||
if r != nil {
|
||||
n = 1
|
||||
for p := ring_next(r); p != r; p = p.next {
|
||||
n += 1
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
package container
|
||||
|
||||
Set :: struct {
|
||||
hash: Array(int),
|
||||
entries: Array(Set_Entry),
|
||||
}
|
||||
|
||||
Set_Entry :: struct {
|
||||
key: u64,
|
||||
next: int,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
set_init :: proc{
|
||||
set_init_none,
|
||||
set_init_cap,
|
||||
}
|
||||
set_delete
|
||||
|
||||
set_in
|
||||
set_not_in
|
||||
set_add
|
||||
set_remove
|
||||
set_reserve
|
||||
set_clear
|
||||
*/
|
||||
|
||||
set_init :: proc{set_init_none, set_init_cap}
|
||||
|
||||
set_init_none :: proc(m: ^Set, allocator := context.allocator) {
|
||||
m.hash.allocator = allocator
|
||||
m.entries.allocator = allocator
|
||||
}
|
||||
|
||||
set_init_cap :: proc(m: ^Set, cap: int, allocator := context.allocator) {
|
||||
m.hash.allocator = allocator
|
||||
m.entries.allocator = allocator
|
||||
set_reserve(m, cap)
|
||||
}
|
||||
|
||||
set_delete :: proc(m: Set) {
|
||||
array_delete(m.hash)
|
||||
array_delete(m.entries)
|
||||
}
|
||||
|
||||
|
||||
set_in :: proc(m: Set, key: u64) -> bool {
|
||||
return _set_find_or_fail(m, key) >= 0
|
||||
}
|
||||
set_not_in :: proc(m: Set, key: u64) -> bool {
|
||||
return _set_find_or_fail(m, key) < 0
|
||||
}
|
||||
|
||||
set_add :: proc(m: ^Set, key: u64) {
|
||||
if array_len(m.hash) == 0 {
|
||||
_set_grow(m)
|
||||
}
|
||||
|
||||
_ = _set_find_or_make(m, key)
|
||||
if _set_full(m^) {
|
||||
_set_grow(m)
|
||||
}
|
||||
}
|
||||
|
||||
set_remove :: proc(m: ^Set, key: u64) {
|
||||
fr := _set_find_key(m^, key)
|
||||
if fr.entry_index >= 0 {
|
||||
_set_erase(m, fr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
set_reserve :: proc(m: ^Set, new_size: int) {
|
||||
nm: Set
|
||||
set_init(&nm, m.hash.allocator)
|
||||
array_resize(&nm.hash, new_size)
|
||||
array_reserve(&nm.entries, array_len(m.entries))
|
||||
|
||||
for i in 0..<new_size {
|
||||
array_set(&nm.hash, i, -1)
|
||||
}
|
||||
for i in 0..<array_len(m.entries) {
|
||||
e := array_get(m.entries, i)
|
||||
set_add(&nm, e.key)
|
||||
}
|
||||
|
||||
set_delete(m^)
|
||||
m^ = nm
|
||||
}
|
||||
|
||||
set_clear :: proc(m: ^Set) {
|
||||
array_clear(&m.hash)
|
||||
array_clear(&m.entries)
|
||||
}
|
||||
|
||||
|
||||
set_equal :: proc(a, b: Set) -> bool {
|
||||
a_entries := array_slice(a.entries)
|
||||
b_entries := array_slice(b.entries)
|
||||
if len(a_entries) != len(b_entries) {
|
||||
return false
|
||||
}
|
||||
for e in a_entries {
|
||||
if set_not_in(b, e.key) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Internal
|
||||
|
||||
_set_add_entry :: proc(m: ^Set, key: u64) -> int {
|
||||
e: Set_Entry
|
||||
e.key = key
|
||||
e.next = -1
|
||||
idx := array_len(m.entries)
|
||||
array_push(&m.entries, e)
|
||||
return idx
|
||||
}
|
||||
|
||||
_set_erase :: proc(m: ^Set, fr: Map_Find_Result) {
|
||||
if fr.entry_prev < 0 {
|
||||
array_set(&m.hash, fr.hash_index, array_get(m.entries, fr.entry_index).next)
|
||||
} else {
|
||||
array_get_ptr(m.entries, fr.entry_prev).next = array_get(m.entries, fr.entry_index).next
|
||||
}
|
||||
|
||||
if fr.entry_index == array_len(m.entries)-1 {
|
||||
array_pop_back(&m.entries)
|
||||
return
|
||||
}
|
||||
|
||||
array_set(&m.entries, fr.entry_index, array_get(m.entries, array_len(m.entries)-1))
|
||||
last := _set_find_key(m^, array_get(m.entries, fr.entry_index).key)
|
||||
|
||||
if last.entry_prev < 0 {
|
||||
array_get_ptr(m.entries, last.entry_prev).next = fr.entry_index
|
||||
} else {
|
||||
array_set(&m.hash, last.hash_index, fr.entry_index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_set_find_key :: proc(m: Set, key: u64) -> Map_Find_Result {
|
||||
fr: Map_Find_Result
|
||||
fr.hash_index = -1
|
||||
fr.entry_prev = -1
|
||||
fr.entry_index = -1
|
||||
|
||||
if array_len(m.hash) == 0 {
|
||||
return fr
|
||||
}
|
||||
|
||||
fr.hash_index = int(key % u64(array_len(m.hash)))
|
||||
fr.entry_index = array_get(m.hash, fr.hash_index)
|
||||
for fr.entry_index >= 0 {
|
||||
it := array_get_ptr(m.entries, fr.entry_index)
|
||||
if it.key == key {
|
||||
return fr
|
||||
}
|
||||
fr.entry_prev = fr.entry_index
|
||||
fr.entry_index = it.next
|
||||
}
|
||||
return fr
|
||||
}
|
||||
|
||||
_set_find_entry :: proc(m: ^Set, e: ^Set_Entry) -> Map_Find_Result {
|
||||
fr: Map_Find_Result
|
||||
fr.hash_index = -1
|
||||
fr.entry_prev = -1
|
||||
fr.entry_index = -1
|
||||
|
||||
if array_len(m.hash) == 0 {
|
||||
return fr
|
||||
}
|
||||
|
||||
fr.hash_index = int(e.key % u64(array_len(m.hash)))
|
||||
fr.entry_index = array_get(m.hash, fr.hash_index)
|
||||
for fr.entry_index >= 0 {
|
||||
it := array_get_ptr(m.entries, fr.entry_index)
|
||||
if it == e {
|
||||
return fr
|
||||
}
|
||||
fr.entry_prev = fr.entry_index
|
||||
fr.entry_index = it.next
|
||||
}
|
||||
return fr
|
||||
}
|
||||
|
||||
_set_find_or_fail :: proc(m: Set, key: u64) -> int {
|
||||
return _set_find_key(m, key).entry_index
|
||||
}
|
||||
_set_find_or_make :: proc(m: ^Set, key: u64) -> int {
|
||||
fr := _set_find_key(m^, key)
|
||||
if fr.entry_index >= 0 {
|
||||
return fr.entry_index
|
||||
}
|
||||
|
||||
i := _set_add_entry(m, key)
|
||||
if fr.entry_prev < 0 {
|
||||
array_set(&m.hash, fr.hash_index, i)
|
||||
} else {
|
||||
array_get_ptr(m.entries, fr.entry_prev).next = i
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
_set_make :: proc(m: ^Set, key: u64) -> int {
|
||||
fr := _set_find_key(m^, key)
|
||||
i := _set_add_entry(m, key)
|
||||
|
||||
if fr.entry_prev < 0 {
|
||||
array_set(&m.hash, fr.hash_index, i)
|
||||
} else {
|
||||
array_get_ptr(m.entries, fr.entry_prev).next = i
|
||||
}
|
||||
|
||||
array_get_ptr(m.entries, i).next = fr.entry_index
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
_set_full :: proc(m: Set) -> bool {
|
||||
// TODO(bill): Determine good max load factor
|
||||
return array_len(m.entries) >= (array_len(m.hash) / 4)*3
|
||||
}
|
||||
|
||||
_set_grow :: proc(m: ^Set) {
|
||||
new_size := array_len(m.entries) * 4 + 7 // TODO(bill): Determine good grow rate
|
||||
set_reserve(m, new_size)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
package container
|
||||
|
||||
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||
data: [N]T,
|
||||
len: int,
|
||||
}
|
||||
|
||||
|
||||
small_array_len :: proc(a: $A/Small_Array) -> int {
|
||||
return a.len
|
||||
}
|
||||
|
||||
small_array_cap :: proc(a: $A/Small_Array) -> int {
|
||||
return len(a.data)
|
||||
}
|
||||
|
||||
small_array_space :: proc(a: $A/Small_Array) -> int {
|
||||
return len(a.data) - a.len
|
||||
}
|
||||
|
||||
small_array_slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
|
||||
return a.data[:a.len]
|
||||
}
|
||||
|
||||
|
||||
small_array_get :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> T {
|
||||
return a.data[index]
|
||||
}
|
||||
small_array_get_ptr :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> ^T {
|
||||
return &a.data[index]
|
||||
}
|
||||
|
||||
small_array_set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T, loc := #caller_location) {
|
||||
a.data[index] = item
|
||||
}
|
||||
|
||||
small_array_resize :: proc(a: ^$A/Small_Array, length: int) {
|
||||
a.len = min(length, len(a.data))
|
||||
}
|
||||
|
||||
|
||||
small_array_push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
if a.len < len(a.data) {
|
||||
a.len += 1
|
||||
a.data[a.len-1] = item
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
small_array_push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
if a.len < len(a.data) {
|
||||
a.len += 1
|
||||
data := small_array_slice(a)
|
||||
copy(data[1:], data[:])
|
||||
data[0] = item
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
small_array_pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||
assert(condition=a.len > 0, loc=loc)
|
||||
item := a.data[a.len-1]
|
||||
a.len -= 1
|
||||
return item
|
||||
}
|
||||
|
||||
small_array_pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||
assert(condition=a.len > 0, loc=loc)
|
||||
item := a.data[0]
|
||||
s := small_array_slice(a)
|
||||
copy(s[:], s[1:])
|
||||
a.len -= 1
|
||||
return item
|
||||
}
|
||||
|
||||
|
||||
small_array_consume :: proc(a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) {
|
||||
assert(condition=a.len >= count, loc=loc)
|
||||
a.len -= count
|
||||
}
|
||||
|
||||
small_array_clear :: proc(a: ^$A/Small_Array($N, $T)) {
|
||||
small_array_resize(a, 0)
|
||||
}
|
||||
|
||||
small_array_push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) {
|
||||
n := copy(a.data[a.len:], items[:])
|
||||
a.len += n
|
||||
}
|
||||
|
||||
small_array_push :: proc{small_array_push_back, small_array_push_back_elems}
|
||||
small_array_append :: proc{small_array_push_back, small_array_push_back_elems}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package container_small_array
|
||||
|
||||
import "core:builtin"
|
||||
|
||||
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||
data: [N]T,
|
||||
len: int,
|
||||
}
|
||||
|
||||
|
||||
len :: proc(a: $A/Small_Array) -> int {
|
||||
return a.len
|
||||
}
|
||||
|
||||
cap :: proc(a: $A/Small_Array) -> int {
|
||||
return builtin.len(a.data)
|
||||
}
|
||||
|
||||
space :: proc(a: $A/Small_Array) -> int {
|
||||
return builtin.len(a.data) - a.len
|
||||
}
|
||||
|
||||
slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
|
||||
return a.data[:a.len]
|
||||
}
|
||||
|
||||
|
||||
get :: proc(a: $A/Small_Array($N, $T), index: int) -> T {
|
||||
return a.data[index]
|
||||
}
|
||||
get_ptr :: proc(a: ^$A/Small_Array($N, $T), index: int) -> ^T {
|
||||
return &a.data[index]
|
||||
}
|
||||
|
||||
set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||
a.data[index] = item
|
||||
}
|
||||
|
||||
resize :: proc(a: ^$A/Small_Array, length: int) {
|
||||
a.len = min(length, builtin.len(a.data))
|
||||
}
|
||||
|
||||
|
||||
push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
if a.len < cap(a^) {
|
||||
a.data[a.len] = item
|
||||
a.len += 1
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
if a.len < cap(a^) {
|
||||
a.len += 1
|
||||
data := slice(a)
|
||||
copy(data[1:], data[:])
|
||||
data[0] = item
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||
assert(condition=(N > 0 && a.len > 0), loc=loc)
|
||||
item := a.data[a.len-1]
|
||||
a.len -= 1
|
||||
return item
|
||||
}
|
||||
|
||||
pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||
assert(condition=(N > 0 && a.len > 0), loc=loc)
|
||||
item := a.data[0]
|
||||
s := slice(a)
|
||||
copy(s[:], s[1:])
|
||||
a.len -= 1
|
||||
return item
|
||||
}
|
||||
|
||||
pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||
if N > 0 && a.len > 0 {
|
||||
item = a.data[a.len-1]
|
||||
a.len -= 1
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||
if N > 0 && a.len > 0 {
|
||||
item = a.data[0]
|
||||
s := slice(a)
|
||||
copy(s[:], s[1:])
|
||||
a.len -= 1
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
consume :: proc(a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) {
|
||||
assert(condition=a.len >= count, loc=loc)
|
||||
a.len -= count
|
||||
}
|
||||
|
||||
clear :: proc(a: ^$A/Small_Array($N, $T)) {
|
||||
resize(a, 0)
|
||||
}
|
||||
|
||||
push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) {
|
||||
n := copy(a.data[a.len:], items[:])
|
||||
a.len += n
|
||||
}
|
||||
|
||||
append_elem :: push_back
|
||||
append_elems :: push_back_elems
|
||||
push :: proc{push_back, push_back_elems}
|
||||
append :: proc{push_back, push_back_elems}
|
||||
@@ -0,0 +1,98 @@
|
||||
// The following is a generic O(V+E) topological sorter implementation.
|
||||
// This is the fastest known method for topological sorting and Odin's
|
||||
// map type is being used to accelerate lookups.
|
||||
package container_topological_sort
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
_ :: intrinsics
|
||||
_ :: runtime
|
||||
|
||||
|
||||
Relations :: struct($K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||
dependents: map[K]bool,
|
||||
dependencies: int,
|
||||
}
|
||||
|
||||
Sorter :: struct(K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||
relations: map[K]Relations(K),
|
||||
dependents_allocator: runtime.Allocator,
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
make_relations :: proc(sorter: ^$S/Sorter($K)) -> (r: Relations(K)) {
|
||||
r.dependents.allocator = sorter.dependents_allocator
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
init :: proc(sorter: ^$S/Sorter($K)) {
|
||||
sorter.relations = make(map[K]Relations(K))
|
||||
sorter.dependents_allocator = context.allocator
|
||||
}
|
||||
|
||||
destroy :: proc(sorter: ^$S/Sorter($K)) {
|
||||
for _, v in &sorter.relations {
|
||||
delete(v.dependents)
|
||||
}
|
||||
delete(sorter.relations)
|
||||
}
|
||||
|
||||
add_key :: proc(sorter: ^$S/Sorter($K), key: K) -> bool {
|
||||
if key in sorter.relations {
|
||||
return false
|
||||
}
|
||||
sorter.relations[key] = make_relations(sorter)
|
||||
return true
|
||||
}
|
||||
|
||||
add_dependency :: proc(sorter: ^$S/Sorter($K), key, dependency: K) -> bool {
|
||||
if key == dependency {
|
||||
return false
|
||||
}
|
||||
|
||||
find := &sorter.relations[dependency]
|
||||
if find == nil {
|
||||
find = map_insert(&sorter.relations, dependency, make_relations(sorter))
|
||||
}
|
||||
|
||||
if find.dependents[key] {
|
||||
return true
|
||||
}
|
||||
find.dependents[key] = true
|
||||
|
||||
find = &sorter.relations[key]
|
||||
if find == nil {
|
||||
find = map_insert(&sorter.relations, key, make_relations(sorter))
|
||||
}
|
||||
|
||||
find.dependencies += 1
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) {
|
||||
relations := &sorter.relations
|
||||
|
||||
for k, v in relations {
|
||||
if v.dependencies == 0 {
|
||||
append(&sorted, k)
|
||||
}
|
||||
}
|
||||
|
||||
for root in &sorted do for k, _ in relations[root].dependents {
|
||||
relation := &relations[k]
|
||||
relation.dependencies -= 1
|
||||
if relation.dependencies == 0 {
|
||||
append(&sorted, k)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v in relations {
|
||||
if v.dependencies != 0 {
|
||||
append(&cycled, k)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
# crypto
|
||||
A crypto library for the Odin language
|
||||
|
||||
## Supported
|
||||
This library offers various algorithms implemented in Odin.
|
||||
Please see the chart below for the options.
|
||||
|
||||
## Hashing algorithms
|
||||
| Algorithm | |
|
||||
|:-------------------------------------------------------------------------------------------------------------|:-----------------|
|
||||
| [BLAKE](https://web.archive.org/web/20190915215948/https://131002.net/blake) | ✔️ |
|
||||
| [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ |
|
||||
| [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ |
|
||||
| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ |
|
||||
| [Grøstl](http://www.groestl.info/Groestl.zip) | ✔️ |
|
||||
| [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ |
|
||||
| [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ |
|
||||
| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ |
|
||||
| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ |
|
||||
| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ |
|
||||
| [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ |
|
||||
| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ |
|
||||
| [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ |
|
||||
| [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ |
|
||||
| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ |
|
||||
| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ |
|
||||
| [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ |
|
||||
| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ |
|
||||
|
||||
#### High level API
|
||||
Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_<size>`\*.
|
||||
Included in these groups are six procedures.
|
||||
* `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally
|
||||
* `hash_bytes` - Hash a given byte slice and return the computed hash
|
||||
* `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally
|
||||
* `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash
|
||||
* `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it
|
||||
* `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true)
|
||||
|
||||
\* On some algorithms there is another part to the name, since they might offer control about additional parameters.
|
||||
For instance, `HAVAL` offers different sizes as well as three different round amounts.
|
||||
Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.hash_256_3(...)`.
|
||||
|
||||
#### Low level API
|
||||
The above mentioned procedures internally call three procedures: `init`, `update` and `final`.
|
||||
You may also directly call them, if you wish.
|
||||
|
||||
#### Example
|
||||
```odin
|
||||
package crypto_example
|
||||
|
||||
// Import the desired package
|
||||
import "core:crypto/md4"
|
||||
|
||||
main :: proc() {
|
||||
input := "foo"
|
||||
|
||||
// Compute the hash, using the high level API
|
||||
computed_hash := md4.hash(input)
|
||||
|
||||
// Variant that takes a destination buffer, instead of returning the computed hash
|
||||
hash := make([]byte, md4.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash
|
||||
md4.hash(input, hash[:])
|
||||
|
||||
// Compute the hash, using the low level API
|
||||
ctx: md4.Md4_Context
|
||||
computed_hash_low: [16]byte
|
||||
md4.init(&ctx)
|
||||
md4.update(&ctx, transmute([]byte)input)
|
||||
md4.final(&ctx, computed_hash_low[:])
|
||||
}
|
||||
```
|
||||
For example uses of all available algorithms, please see the tests within `tests/core/crypto`.
|
||||
|
||||
#### Thread safety
|
||||
The crypto package is not thread-safe at the moment. This may change in the future.
|
||||
|
||||
### Disclaimer
|
||||
The algorithms were ported out of curiosity and due to interest in the field.
|
||||
We have not had any of the code verified by a third party or tested/fuzzed by any automatic means.
|
||||
Whereever we were able to find official test vectors, those were used to verify the implementation.
|
||||
We do not recommend using them in a production environment, without any additional testing and/or verification.
|
||||
|
||||
### ToDo
|
||||
* Ciphers (Symmetric, Asymmetric)
|
||||
* MACs (Message Authentication Code)
|
||||
* CSPRNGs (Cryptographically Secure PseudoRandom Number Generator)
|
||||
* KDFs (Key Derivation Function)
|
||||
* KEAs (Key Exchange Algorithm)
|
||||
|
||||
### License
|
||||
This library is made available under the BSD-3 license.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
# fiat
|
||||
|
||||
This package contains low level arithmetic required to implement certain
|
||||
cryptographic primitives, ported from the [fiat-crypto project][1]
|
||||
along with some higher-level helpers.
|
||||
|
||||
## Notes
|
||||
|
||||
fiat-crypto gives the choice of 3 licenses for derived works. The 1-Clause
|
||||
BSD license is chosen as it is compatible with Odin's existing licensing.
|
||||
|
||||
The routines are intended to be timing-safe, as long as the underlying
|
||||
integer arithmetic is constant time. This is true on most systems commonly
|
||||
used today, with the notable exception of WASM.
|
||||
|
||||
While fiat-crypto provides both output targeting both 32-bit and 64-bit
|
||||
architectures, only the 64-bit versions were used, as 32-bit architectures
|
||||
are becoming increasingly uncommon and irrelevant.
|
||||
|
||||
With the current Odin syntax, the Go output is trivially ported in most
|
||||
cases and was used as the basis of the port.
|
||||
|
||||
In the future, it would be better to auto-generate Odin either directly
|
||||
by adding an appropriate code-gen backend written in Coq, or perhaps by
|
||||
parsing the JSON output.
|
||||
|
||||
As this is a port rather than autogenerated output, none of fiat-crypto's
|
||||
formal verification guarantees apply, unless it is possible to prove binary
|
||||
equivalence.
|
||||
|
||||
For the most part, alterations to the base fiat-crypto generated code was
|
||||
kept to a minimum, to aid auditability. This results in a somewhat
|
||||
ideosyncratic style, and in some cases minor performance penalties.
|
||||
|
||||
[1]: https://github.com/mit-plv/fiat-crypto
|
||||
@@ -0,0 +1,24 @@
|
||||
package fiat
|
||||
|
||||
// This package provides various helpers and types common to all of the
|
||||
// fiat-crypto derived backends.
|
||||
|
||||
// This code only works on a two's complement system.
|
||||
#assert((-1 & 3) == 3)
|
||||
|
||||
u1 :: distinct u8
|
||||
i1 :: distinct i8
|
||||
|
||||
cmovznz_u64 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
|
||||
x1 := (u64(arg1) * 0xffffffffffffffff)
|
||||
x2 := ((x1 & arg3) | ((~x1) & arg2))
|
||||
out1 = x2
|
||||
return
|
||||
}
|
||||
|
||||
cmovznz_u32 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) {
|
||||
x1 := (u32(arg1) * 0xffffffff)
|
||||
x2 := ((x1 & arg3) | ((~x1) & arg2))
|
||||
out1 = x2
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package field_curve25519
|
||||
|
||||
import "core:crypto"
|
||||
import "core:mem"
|
||||
|
||||
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element {
|
||||
return transmute(^Loose_Field_Element)(arg1)
|
||||
}
|
||||
|
||||
fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element {
|
||||
return transmute(^Tight_Field_Element)(arg1)
|
||||
}
|
||||
|
||||
fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) {
|
||||
// Ignore the unused bit by copying the input and masking the bit off
|
||||
// prior to deserialization.
|
||||
tmp1: [32]byte = ---
|
||||
copy_slice(tmp1[:], arg1[:])
|
||||
tmp1[31] &= 127
|
||||
|
||||
_fe_from_bytes(out1, &tmp1)
|
||||
|
||||
mem.zero_explicit(&tmp1, size_of(tmp1))
|
||||
}
|
||||
|
||||
fe_equal :: proc "contextless" (arg1, arg2: ^Tight_Field_Element) -> int {
|
||||
tmp2: [32]byte = ---
|
||||
|
||||
fe_to_bytes(&tmp2, arg2)
|
||||
ret := fe_equal_bytes(arg1, &tmp2)
|
||||
|
||||
mem.zero_explicit(&tmp2, size_of(tmp2))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
fe_equal_bytes :: proc "contextless" (arg1: ^Tight_Field_Element, arg2: ^[32]byte) -> int {
|
||||
tmp1: [32]byte = ---
|
||||
|
||||
fe_to_bytes(&tmp1, arg1)
|
||||
|
||||
ret := crypto.compare_constant_time(tmp1[:], arg2[:])
|
||||
|
||||
mem.zero_explicit(&tmp1, size_of(tmp1))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
fe_carry_pow2k :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element, arg2: uint) {
|
||||
// Special case: `arg1^(2 * 0) = 1`, though this should never happen.
|
||||
if arg2 == 0 {
|
||||
fe_one(out1)
|
||||
return
|
||||
}
|
||||
|
||||
fe_carry_square(out1, arg1)
|
||||
for _ in 1..<arg2 {
|
||||
fe_carry_square(out1, fe_relax_cast(out1))
|
||||
}
|
||||
}
|
||||
|
||||
fe_carry_opp :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
fe_opp(fe_relax_cast(out1), arg1)
|
||||
fe_carry(out1, fe_relax_cast(out1))
|
||||
}
|
||||
|
||||
fe_carry_invsqrt :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) -> int {
|
||||
// Inverse square root taken from Monocypher.
|
||||
|
||||
tmp1, tmp2, tmp3: Tight_Field_Element = ---, ---, ---
|
||||
|
||||
// t0 = x^((p-5)/8)
|
||||
// Can be achieved with a simple double & add ladder,
|
||||
// but it would be slower.
|
||||
fe_carry_pow2k(&tmp1, arg1, 1)
|
||||
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 2)
|
||||
fe_carry_mul(&tmp2, arg1, fe_relax_cast(&tmp2))
|
||||
fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), fe_relax_cast(&tmp2))
|
||||
fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 1)
|
||||
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
|
||||
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 5)
|
||||
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
|
||||
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 10)
|
||||
fe_carry_mul(&tmp2, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
|
||||
fe_carry_pow2k(&tmp3, fe_relax_cast(&tmp2), 20)
|
||||
fe_carry_mul(&tmp2, fe_relax_cast(&tmp3), fe_relax_cast(&tmp2))
|
||||
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 10)
|
||||
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
|
||||
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 50)
|
||||
fe_carry_mul(&tmp2, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
|
||||
fe_carry_pow2k(&tmp3, fe_relax_cast(&tmp2), 100)
|
||||
fe_carry_mul(&tmp2, fe_relax_cast(&tmp3), fe_relax_cast(&tmp2))
|
||||
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 50)
|
||||
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
|
||||
fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 2)
|
||||
fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), arg1)
|
||||
|
||||
// quartic = x^((p-1)/4)
|
||||
quartic := &tmp2
|
||||
fe_carry_square(quartic, fe_relax_cast(&tmp1))
|
||||
fe_carry_mul(quartic, fe_relax_cast(quartic), arg1)
|
||||
|
||||
// Serialize quartic once to save on repeated serialization/sanitization.
|
||||
quartic_buf: [32]byte = ---
|
||||
fe_to_bytes(&quartic_buf, quartic)
|
||||
check := &tmp3
|
||||
|
||||
fe_one(check)
|
||||
p1 := fe_equal_bytes(check, &quartic_buf)
|
||||
fe_carry_opp(check, check)
|
||||
m1 := fe_equal_bytes(check, &quartic_buf)
|
||||
fe_carry_opp(check, &SQRT_M1)
|
||||
ms := fe_equal_bytes(check, &quartic_buf)
|
||||
|
||||
// if quartic == -1 or sqrt(-1)
|
||||
// then isr = x^((p-1)/4) * sqrt(-1)
|
||||
// else isr = x^((p-1)/4)
|
||||
fe_carry_mul(out1, fe_relax_cast(&tmp1), fe_relax_cast(&SQRT_M1))
|
||||
fe_cond_assign(out1, &tmp1, (m1|ms) ~ 1)
|
||||
|
||||
mem.zero_explicit(&tmp1, size_of(tmp1))
|
||||
mem.zero_explicit(&tmp2, size_of(tmp2))
|
||||
mem.zero_explicit(&tmp3, size_of(tmp3))
|
||||
mem.zero_explicit(&quartic_buf, size_of(quartic_buf))
|
||||
|
||||
return p1 | m1
|
||||
}
|
||||
|
||||
fe_carry_inv :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
|
||||
tmp1: Tight_Field_Element
|
||||
|
||||
fe_carry_square(&tmp1, arg1)
|
||||
_ = fe_carry_invsqrt(&tmp1, fe_relax_cast(&tmp1))
|
||||
fe_carry_square(&tmp1, fe_relax_cast(&tmp1))
|
||||
fe_carry_mul(out1, fe_relax_cast(&tmp1), arg1)
|
||||
|
||||
mem.zero_explicit(&tmp1, size_of(tmp1))
|
||||
}
|
||||
@@ -0,0 +1,616 @@
|
||||
// The BSD 1-Clause License (BSD-1-Clause)
|
||||
//
|
||||
// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file)
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
|
||||
// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package field_curve25519
|
||||
|
||||
// The file provides arithmetic on the field Z/(2^255-19) using
|
||||
// unsaturated 64-bit integer arithmetic. It is derived primarily
|
||||
// from the machine generated Golang output from the fiat-crypto project.
|
||||
//
|
||||
// While the base implementation is provably correct, this implementation
|
||||
// makes no such claims as the port and optimizations were done by hand.
|
||||
// At some point, it may be worth adding support to fiat-crypto for
|
||||
// generating Odin output.
|
||||
//
|
||||
// TODO:
|
||||
// * When fiat-crypto supports it, using a saturated 64-bit limbs
|
||||
// instead of 51-bit limbs will be faster, though the gains are
|
||||
// minimal unless adcx/adox/mulx are used.
|
||||
|
||||
import fiat "core:crypto/_fiat"
|
||||
import "core:math/bits"
|
||||
|
||||
Loose_Field_Element :: distinct [5]u64
|
||||
Tight_Field_Element :: distinct [5]u64
|
||||
|
||||
SQRT_M1 := Tight_Field_Element{
|
||||
1718705420411056,
|
||||
234908883556509,
|
||||
2233514472574048,
|
||||
2117202627021982,
|
||||
765476049583133,
|
||||
}
|
||||
|
||||
_addcarryx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
|
||||
x1 := ((u64(arg1) + arg2) + arg3)
|
||||
x2 := (x1 & 0x7ffffffffffff)
|
||||
x3 := fiat.u1((x1 >> 51))
|
||||
out1 = x2
|
||||
out2 = x3
|
||||
return
|
||||
}
|
||||
|
||||
_subborrowx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
|
||||
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
|
||||
x2 := fiat.i1((x1 >> 51))
|
||||
x3 := (u64(x1) & 0x7ffffffffffff)
|
||||
out1 = x3
|
||||
out2 = (0x0 - fiat.u1(x2))
|
||||
return
|
||||
}
|
||||
|
||||
fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) {
|
||||
x2, x1 := bits.mul_u64(arg1[4], (arg2[4] * 0x13))
|
||||
x4, x3 := bits.mul_u64(arg1[4], (arg2[3] * 0x13))
|
||||
x6, x5 := bits.mul_u64(arg1[4], (arg2[2] * 0x13))
|
||||
x8, x7 := bits.mul_u64(arg1[4], (arg2[1] * 0x13))
|
||||
x10, x9 := bits.mul_u64(arg1[3], (arg2[4] * 0x13))
|
||||
x12, x11 := bits.mul_u64(arg1[3], (arg2[3] * 0x13))
|
||||
x14, x13 := bits.mul_u64(arg1[3], (arg2[2] * 0x13))
|
||||
x16, x15 := bits.mul_u64(arg1[2], (arg2[4] * 0x13))
|
||||
x18, x17 := bits.mul_u64(arg1[2], (arg2[3] * 0x13))
|
||||
x20, x19 := bits.mul_u64(arg1[1], (arg2[4] * 0x13))
|
||||
x22, x21 := bits.mul_u64(arg1[4], arg2[0])
|
||||
x24, x23 := bits.mul_u64(arg1[3], arg2[1])
|
||||
x26, x25 := bits.mul_u64(arg1[3], arg2[0])
|
||||
x28, x27 := bits.mul_u64(arg1[2], arg2[2])
|
||||
x30, x29 := bits.mul_u64(arg1[2], arg2[1])
|
||||
x32, x31 := bits.mul_u64(arg1[2], arg2[0])
|
||||
x34, x33 := bits.mul_u64(arg1[1], arg2[3])
|
||||
x36, x35 := bits.mul_u64(arg1[1], arg2[2])
|
||||
x38, x37 := bits.mul_u64(arg1[1], arg2[1])
|
||||
x40, x39 := bits.mul_u64(arg1[1], arg2[0])
|
||||
x42, x41 := bits.mul_u64(arg1[0], arg2[4])
|
||||
x44, x43 := bits.mul_u64(arg1[0], arg2[3])
|
||||
x46, x45 := bits.mul_u64(arg1[0], arg2[2])
|
||||
x48, x47 := bits.mul_u64(arg1[0], arg2[1])
|
||||
x50, x49 := bits.mul_u64(arg1[0], arg2[0])
|
||||
x51, x52 := bits.add_u64(x13, x7, u64(0x0))
|
||||
x53, _ := bits.add_u64(x14, x8, u64(fiat.u1(x52)))
|
||||
x55, x56 := bits.add_u64(x17, x51, u64(0x0))
|
||||
x57, _ := bits.add_u64(x18, x53, u64(fiat.u1(x56)))
|
||||
x59, x60 := bits.add_u64(x19, x55, u64(0x0))
|
||||
x61, _ := bits.add_u64(x20, x57, u64(fiat.u1(x60)))
|
||||
x63, x64 := bits.add_u64(x49, x59, u64(0x0))
|
||||
x65, _ := bits.add_u64(x50, x61, u64(fiat.u1(x64)))
|
||||
x67 := ((x63 >> 51) | ((x65 << 13) & 0xffffffffffffffff))
|
||||
x68 := (x63 & 0x7ffffffffffff)
|
||||
x69, x70 := bits.add_u64(x23, x21, u64(0x0))
|
||||
x71, _ := bits.add_u64(x24, x22, u64(fiat.u1(x70)))
|
||||
x73, x74 := bits.add_u64(x27, x69, u64(0x0))
|
||||
x75, _ := bits.add_u64(x28, x71, u64(fiat.u1(x74)))
|
||||
x77, x78 := bits.add_u64(x33, x73, u64(0x0))
|
||||
x79, _ := bits.add_u64(x34, x75, u64(fiat.u1(x78)))
|
||||
x81, x82 := bits.add_u64(x41, x77, u64(0x0))
|
||||
x83, _ := bits.add_u64(x42, x79, u64(fiat.u1(x82)))
|
||||
x85, x86 := bits.add_u64(x25, x1, u64(0x0))
|
||||
x87, _ := bits.add_u64(x26, x2, u64(fiat.u1(x86)))
|
||||
x89, x90 := bits.add_u64(x29, x85, u64(0x0))
|
||||
x91, _ := bits.add_u64(x30, x87, u64(fiat.u1(x90)))
|
||||
x93, x94 := bits.add_u64(x35, x89, u64(0x0))
|
||||
x95, _ := bits.add_u64(x36, x91, u64(fiat.u1(x94)))
|
||||
x97, x98 := bits.add_u64(x43, x93, u64(0x0))
|
||||
x99, _ := bits.add_u64(x44, x95, u64(fiat.u1(x98)))
|
||||
x101, x102 := bits.add_u64(x9, x3, u64(0x0))
|
||||
x103, _ := bits.add_u64(x10, x4, u64(fiat.u1(x102)))
|
||||
x105, x106 := bits.add_u64(x31, x101, u64(0x0))
|
||||
x107, _ := bits.add_u64(x32, x103, u64(fiat.u1(x106)))
|
||||
x109, x110 := bits.add_u64(x37, x105, u64(0x0))
|
||||
x111, _ := bits.add_u64(x38, x107, u64(fiat.u1(x110)))
|
||||
x113, x114 := bits.add_u64(x45, x109, u64(0x0))
|
||||
x115, _ := bits.add_u64(x46, x111, u64(fiat.u1(x114)))
|
||||
x117, x118 := bits.add_u64(x11, x5, u64(0x0))
|
||||
x119, _ := bits.add_u64(x12, x6, u64(fiat.u1(x118)))
|
||||
x121, x122 := bits.add_u64(x15, x117, u64(0x0))
|
||||
x123, _ := bits.add_u64(x16, x119, u64(fiat.u1(x122)))
|
||||
x125, x126 := bits.add_u64(x39, x121, u64(0x0))
|
||||
x127, _ := bits.add_u64(x40, x123, u64(fiat.u1(x126)))
|
||||
x129, x130 := bits.add_u64(x47, x125, u64(0x0))
|
||||
x131, _ := bits.add_u64(x48, x127, u64(fiat.u1(x130)))
|
||||
x133, x134 := bits.add_u64(x67, x129, u64(0x0))
|
||||
x135 := (u64(fiat.u1(x134)) + x131)
|
||||
x136 := ((x133 >> 51) | ((x135 << 13) & 0xffffffffffffffff))
|
||||
x137 := (x133 & 0x7ffffffffffff)
|
||||
x138, x139 := bits.add_u64(x136, x113, u64(0x0))
|
||||
x140 := (u64(fiat.u1(x139)) + x115)
|
||||
x141 := ((x138 >> 51) | ((x140 << 13) & 0xffffffffffffffff))
|
||||
x142 := (x138 & 0x7ffffffffffff)
|
||||
x143, x144 := bits.add_u64(x141, x97, u64(0x0))
|
||||
x145 := (u64(fiat.u1(x144)) + x99)
|
||||
x146 := ((x143 >> 51) | ((x145 << 13) & 0xffffffffffffffff))
|
||||
x147 := (x143 & 0x7ffffffffffff)
|
||||
x148, x149 := bits.add_u64(x146, x81, u64(0x0))
|
||||
x150 := (u64(fiat.u1(x149)) + x83)
|
||||
x151 := ((x148 >> 51) | ((x150 << 13) & 0xffffffffffffffff))
|
||||
x152 := (x148 & 0x7ffffffffffff)
|
||||
x153 := (x151 * 0x13)
|
||||
x154 := (x68 + x153)
|
||||
x155 := (x154 >> 51)
|
||||
x156 := (x154 & 0x7ffffffffffff)
|
||||
x157 := (x155 + x137)
|
||||
x158 := fiat.u1((x157 >> 51))
|
||||
x159 := (x157 & 0x7ffffffffffff)
|
||||
x160 := (u64(x158) + x142)
|
||||
out1[0] = x156
|
||||
out1[1] = x159
|
||||
out1[2] = x160
|
||||
out1[3] = x147
|
||||
out1[4] = x152
|
||||
}
|
||||
|
||||
fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
|
||||
x1 := (arg1[4] * 0x13)
|
||||
x2 := (x1 * 0x2)
|
||||
x3 := (arg1[4] * 0x2)
|
||||
x4 := (arg1[3] * 0x13)
|
||||
x5 := (x4 * 0x2)
|
||||
x6 := (arg1[3] * 0x2)
|
||||
x7 := (arg1[2] * 0x2)
|
||||
x8 := (arg1[1] * 0x2)
|
||||
x10, x9 := bits.mul_u64(arg1[4], x1)
|
||||
x12, x11 := bits.mul_u64(arg1[3], x2)
|
||||
x14, x13 := bits.mul_u64(arg1[3], x4)
|
||||
x16, x15 := bits.mul_u64(arg1[2], x2)
|
||||
x18, x17 := bits.mul_u64(arg1[2], x5)
|
||||
x20, x19 := bits.mul_u64(arg1[2], arg1[2])
|
||||
x22, x21 := bits.mul_u64(arg1[1], x2)
|
||||
x24, x23 := bits.mul_u64(arg1[1], x6)
|
||||
x26, x25 := bits.mul_u64(arg1[1], x7)
|
||||
x28, x27 := bits.mul_u64(arg1[1], arg1[1])
|
||||
x30, x29 := bits.mul_u64(arg1[0], x3)
|
||||
x32, x31 := bits.mul_u64(arg1[0], x6)
|
||||
x34, x33 := bits.mul_u64(arg1[0], x7)
|
||||
x36, x35 := bits.mul_u64(arg1[0], x8)
|
||||
x38, x37 := bits.mul_u64(arg1[0], arg1[0])
|
||||
x39, x40 := bits.add_u64(x21, x17, u64(0x0))
|
||||
x41, _ := bits.add_u64(x22, x18, u64(fiat.u1(x40)))
|
||||
x43, x44 := bits.add_u64(x37, x39, u64(0x0))
|
||||
x45, _ := bits.add_u64(x38, x41, u64(fiat.u1(x44)))
|
||||
x47 := ((x43 >> 51) | ((x45 << 13) & 0xffffffffffffffff))
|
||||
x48 := (x43 & 0x7ffffffffffff)
|
||||
x49, x50 := bits.add_u64(x23, x19, u64(0x0))
|
||||
x51, _ := bits.add_u64(x24, x20, u64(fiat.u1(x50)))
|
||||
x53, x54 := bits.add_u64(x29, x49, u64(0x0))
|
||||
x55, _ := bits.add_u64(x30, x51, u64(fiat.u1(x54)))
|
||||
x57, x58 := bits.add_u64(x25, x9, u64(0x0))
|
||||
x59, _ := bits.add_u64(x26, x10, u64(fiat.u1(x58)))
|
||||
x61, x62 := bits.add_u64(x31, x57, u64(0x0))
|
||||
x63, _ := bits.add_u64(x32, x59, u64(fiat.u1(x62)))
|
||||
x65, x66 := bits.add_u64(x27, x11, u64(0x0))
|
||||
x67, _ := bits.add_u64(x28, x12, u64(fiat.u1(x66)))
|
||||
x69, x70 := bits.add_u64(x33, x65, u64(0x0))
|
||||
x71, _ := bits.add_u64(x34, x67, u64(fiat.u1(x70)))
|
||||
x73, x74 := bits.add_u64(x15, x13, u64(0x0))
|
||||
x75, _ := bits.add_u64(x16, x14, u64(fiat.u1(x74)))
|
||||
x77, x78 := bits.add_u64(x35, x73, u64(0x0))
|
||||
x79, _ := bits.add_u64(x36, x75, u64(fiat.u1(x78)))
|
||||
x81, x82 := bits.add_u64(x47, x77, u64(0x0))
|
||||
x83 := (u64(fiat.u1(x82)) + x79)
|
||||
x84 := ((x81 >> 51) | ((x83 << 13) & 0xffffffffffffffff))
|
||||
x85 := (x81 & 0x7ffffffffffff)
|
||||
x86, x87 := bits.add_u64(x84, x69, u64(0x0))
|
||||
x88 := (u64(fiat.u1(x87)) + x71)
|
||||
x89 := ((x86 >> 51) | ((x88 << 13) & 0xffffffffffffffff))
|
||||
x90 := (x86 & 0x7ffffffffffff)
|
||||
x91, x92 := bits.add_u64(x89, x61, u64(0x0))
|
||||
x93 := (u64(fiat.u1(x92)) + x63)
|
||||
x94 := ((x91 >> 51) | ((x93 << 13) & 0xffffffffffffffff))
|
||||
x95 := (x91 & 0x7ffffffffffff)
|
||||
x96, x97 := bits.add_u64(x94, x53, u64(0x0))
|
||||
x98 := (u64(fiat.u1(x97)) + x55)
|
||||
x99 := ((x96 >> 51) | ((x98 << 13) & 0xffffffffffffffff))
|
||||
x100 := (x96 & 0x7ffffffffffff)
|
||||
x101 := (x99 * 0x13)
|
||||
x102 := (x48 + x101)
|
||||
x103 := (x102 >> 51)
|
||||
x104 := (x102 & 0x7ffffffffffff)
|
||||
x105 := (x103 + x85)
|
||||
x106 := fiat.u1((x105 >> 51))
|
||||
x107 := (x105 & 0x7ffffffffffff)
|
||||
x108 := (u64(x106) + x90)
|
||||
out1[0] = x104
|
||||
out1[1] = x107
|
||||
out1[2] = x108
|
||||
out1[3] = x95
|
||||
out1[4] = x100
|
||||
}
|
||||
|
||||
fe_carry :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
|
||||
x1 := arg1[0]
|
||||
x2 := ((x1 >> 51) + arg1[1])
|
||||
x3 := ((x2 >> 51) + arg1[2])
|
||||
x4 := ((x3 >> 51) + arg1[3])
|
||||
x5 := ((x4 >> 51) + arg1[4])
|
||||
x6 := ((x1 & 0x7ffffffffffff) + ((x5 >> 51) * 0x13))
|
||||
x7 := (u64(fiat.u1((x6 >> 51))) + (x2 & 0x7ffffffffffff))
|
||||
x8 := (x6 & 0x7ffffffffffff)
|
||||
x9 := (x7 & 0x7ffffffffffff)
|
||||
x10 := (u64(fiat.u1((x7 >> 51))) + (x3 & 0x7ffffffffffff))
|
||||
x11 := (x4 & 0x7ffffffffffff)
|
||||
x12 := (x5 & 0x7ffffffffffff)
|
||||
out1[0] = x8
|
||||
out1[1] = x9
|
||||
out1[2] = x10
|
||||
out1[3] = x11
|
||||
out1[4] = x12
|
||||
}
|
||||
|
||||
fe_add :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
|
||||
x1 := (arg1[0] + arg2[0])
|
||||
x2 := (arg1[1] + arg2[1])
|
||||
x3 := (arg1[2] + arg2[2])
|
||||
x4 := (arg1[3] + arg2[3])
|
||||
x5 := (arg1[4] + arg2[4])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_sub :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
|
||||
x1 := ((0xfffffffffffda + arg1[0]) - arg2[0])
|
||||
x2 := ((0xffffffffffffe + arg1[1]) - arg2[1])
|
||||
x3 := ((0xffffffffffffe + arg1[2]) - arg2[2])
|
||||
x4 := ((0xffffffffffffe + arg1[3]) - arg2[3])
|
||||
x5 := ((0xffffffffffffe + arg1[4]) - arg2[4])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
|
||||
x1 := (0xfffffffffffda - arg1[0])
|
||||
x2 := (0xffffffffffffe - arg1[1])
|
||||
x3 := (0xffffffffffffe - arg1[2])
|
||||
x4 := (0xffffffffffffe - arg1[3])
|
||||
x5 := (0xffffffffffffe - arg1[4])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) {
|
||||
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
|
||||
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
|
||||
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
|
||||
x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3])
|
||||
x5 := fiat.cmovznz_u64(fiat.u1(arg2), out1[4], arg1[4])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_to_bytes :: proc "contextless" (out1: ^[32]byte, arg1: ^Tight_Field_Element) {
|
||||
x1, x2 := _subborrowx_u51(0x0, arg1[0], 0x7ffffffffffed)
|
||||
x3, x4 := _subborrowx_u51(x2, arg1[1], 0x7ffffffffffff)
|
||||
x5, x6 := _subborrowx_u51(x4, arg1[2], 0x7ffffffffffff)
|
||||
x7, x8 := _subborrowx_u51(x6, arg1[3], 0x7ffffffffffff)
|
||||
x9, x10 := _subborrowx_u51(x8, arg1[4], 0x7ffffffffffff)
|
||||
x11 := fiat.cmovznz_u64(x10, u64(0x0), 0xffffffffffffffff)
|
||||
x12, x13 := _addcarryx_u51(0x0, x1, (x11 & 0x7ffffffffffed))
|
||||
x14, x15 := _addcarryx_u51(x13, x3, (x11 & 0x7ffffffffffff))
|
||||
x16, x17 := _addcarryx_u51(x15, x5, (x11 & 0x7ffffffffffff))
|
||||
x18, x19 := _addcarryx_u51(x17, x7, (x11 & 0x7ffffffffffff))
|
||||
x20, _ := _addcarryx_u51(x19, x9, (x11 & 0x7ffffffffffff))
|
||||
x22 := (x20 << 4)
|
||||
x23 := (x18 * u64(0x2))
|
||||
x24 := (x16 << 6)
|
||||
x25 := (x14 << 3)
|
||||
x26 := (u8(x12) & 0xff)
|
||||
x27 := (x12 >> 8)
|
||||
x28 := (u8(x27) & 0xff)
|
||||
x29 := (x27 >> 8)
|
||||
x30 := (u8(x29) & 0xff)
|
||||
x31 := (x29 >> 8)
|
||||
x32 := (u8(x31) & 0xff)
|
||||
x33 := (x31 >> 8)
|
||||
x34 := (u8(x33) & 0xff)
|
||||
x35 := (x33 >> 8)
|
||||
x36 := (u8(x35) & 0xff)
|
||||
x37 := u8((x35 >> 8))
|
||||
x38 := (x25 + u64(x37))
|
||||
x39 := (u8(x38) & 0xff)
|
||||
x40 := (x38 >> 8)
|
||||
x41 := (u8(x40) & 0xff)
|
||||
x42 := (x40 >> 8)
|
||||
x43 := (u8(x42) & 0xff)
|
||||
x44 := (x42 >> 8)
|
||||
x45 := (u8(x44) & 0xff)
|
||||
x46 := (x44 >> 8)
|
||||
x47 := (u8(x46) & 0xff)
|
||||
x48 := (x46 >> 8)
|
||||
x49 := (u8(x48) & 0xff)
|
||||
x50 := u8((x48 >> 8))
|
||||
x51 := (x24 + u64(x50))
|
||||
x52 := (u8(x51) & 0xff)
|
||||
x53 := (x51 >> 8)
|
||||
x54 := (u8(x53) & 0xff)
|
||||
x55 := (x53 >> 8)
|
||||
x56 := (u8(x55) & 0xff)
|
||||
x57 := (x55 >> 8)
|
||||
x58 := (u8(x57) & 0xff)
|
||||
x59 := (x57 >> 8)
|
||||
x60 := (u8(x59) & 0xff)
|
||||
x61 := (x59 >> 8)
|
||||
x62 := (u8(x61) & 0xff)
|
||||
x63 := (x61 >> 8)
|
||||
x64 := (u8(x63) & 0xff)
|
||||
x65 := fiat.u1((x63 >> 8))
|
||||
x66 := (x23 + u64(x65))
|
||||
x67 := (u8(x66) & 0xff)
|
||||
x68 := (x66 >> 8)
|
||||
x69 := (u8(x68) & 0xff)
|
||||
x70 := (x68 >> 8)
|
||||
x71 := (u8(x70) & 0xff)
|
||||
x72 := (x70 >> 8)
|
||||
x73 := (u8(x72) & 0xff)
|
||||
x74 := (x72 >> 8)
|
||||
x75 := (u8(x74) & 0xff)
|
||||
x76 := (x74 >> 8)
|
||||
x77 := (u8(x76) & 0xff)
|
||||
x78 := u8((x76 >> 8))
|
||||
x79 := (x22 + u64(x78))
|
||||
x80 := (u8(x79) & 0xff)
|
||||
x81 := (x79 >> 8)
|
||||
x82 := (u8(x81) & 0xff)
|
||||
x83 := (x81 >> 8)
|
||||
x84 := (u8(x83) & 0xff)
|
||||
x85 := (x83 >> 8)
|
||||
x86 := (u8(x85) & 0xff)
|
||||
x87 := (x85 >> 8)
|
||||
x88 := (u8(x87) & 0xff)
|
||||
x89 := (x87 >> 8)
|
||||
x90 := (u8(x89) & 0xff)
|
||||
x91 := u8((x89 >> 8))
|
||||
out1[0] = x26
|
||||
out1[1] = x28
|
||||
out1[2] = x30
|
||||
out1[3] = x32
|
||||
out1[4] = x34
|
||||
out1[5] = x36
|
||||
out1[6] = x39
|
||||
out1[7] = x41
|
||||
out1[8] = x43
|
||||
out1[9] = x45
|
||||
out1[10] = x47
|
||||
out1[11] = x49
|
||||
out1[12] = x52
|
||||
out1[13] = x54
|
||||
out1[14] = x56
|
||||
out1[15] = x58
|
||||
out1[16] = x60
|
||||
out1[17] = x62
|
||||
out1[18] = x64
|
||||
out1[19] = x67
|
||||
out1[20] = x69
|
||||
out1[21] = x71
|
||||
out1[22] = x73
|
||||
out1[23] = x75
|
||||
out1[24] = x77
|
||||
out1[25] = x80
|
||||
out1[26] = x82
|
||||
out1[27] = x84
|
||||
out1[28] = x86
|
||||
out1[29] = x88
|
||||
out1[30] = x90
|
||||
out1[31] = x91
|
||||
}
|
||||
|
||||
_fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) {
|
||||
x1 := (u64(arg1[31]) << 44)
|
||||
x2 := (u64(arg1[30]) << 36)
|
||||
x3 := (u64(arg1[29]) << 28)
|
||||
x4 := (u64(arg1[28]) << 20)
|
||||
x5 := (u64(arg1[27]) << 12)
|
||||
x6 := (u64(arg1[26]) << 4)
|
||||
x7 := (u64(arg1[25]) << 47)
|
||||
x8 := (u64(arg1[24]) << 39)
|
||||
x9 := (u64(arg1[23]) << 31)
|
||||
x10 := (u64(arg1[22]) << 23)
|
||||
x11 := (u64(arg1[21]) << 15)
|
||||
x12 := (u64(arg1[20]) << 7)
|
||||
x13 := (u64(arg1[19]) << 50)
|
||||
x14 := (u64(arg1[18]) << 42)
|
||||
x15 := (u64(arg1[17]) << 34)
|
||||
x16 := (u64(arg1[16]) << 26)
|
||||
x17 := (u64(arg1[15]) << 18)
|
||||
x18 := (u64(arg1[14]) << 10)
|
||||
x19 := (u64(arg1[13]) << 2)
|
||||
x20 := (u64(arg1[12]) << 45)
|
||||
x21 := (u64(arg1[11]) << 37)
|
||||
x22 := (u64(arg1[10]) << 29)
|
||||
x23 := (u64(arg1[9]) << 21)
|
||||
x24 := (u64(arg1[8]) << 13)
|
||||
x25 := (u64(arg1[7]) << 5)
|
||||
x26 := (u64(arg1[6]) << 48)
|
||||
x27 := (u64(arg1[5]) << 40)
|
||||
x28 := (u64(arg1[4]) << 32)
|
||||
x29 := (u64(arg1[3]) << 24)
|
||||
x30 := (u64(arg1[2]) << 16)
|
||||
x31 := (u64(arg1[1]) << 8)
|
||||
x32 := arg1[0]
|
||||
x33 := (x31 + u64(x32))
|
||||
x34 := (x30 + x33)
|
||||
x35 := (x29 + x34)
|
||||
x36 := (x28 + x35)
|
||||
x37 := (x27 + x36)
|
||||
x38 := (x26 + x37)
|
||||
x39 := (x38 & 0x7ffffffffffff)
|
||||
x40 := u8((x38 >> 51))
|
||||
x41 := (x25 + u64(x40))
|
||||
x42 := (x24 + x41)
|
||||
x43 := (x23 + x42)
|
||||
x44 := (x22 + x43)
|
||||
x45 := (x21 + x44)
|
||||
x46 := (x20 + x45)
|
||||
x47 := (x46 & 0x7ffffffffffff)
|
||||
x48 := u8((x46 >> 51))
|
||||
x49 := (x19 + u64(x48))
|
||||
x50 := (x18 + x49)
|
||||
x51 := (x17 + x50)
|
||||
x52 := (x16 + x51)
|
||||
x53 := (x15 + x52)
|
||||
x54 := (x14 + x53)
|
||||
x55 := (x13 + x54)
|
||||
x56 := (x55 & 0x7ffffffffffff)
|
||||
x57 := u8((x55 >> 51))
|
||||
x58 := (x12 + u64(x57))
|
||||
x59 := (x11 + x58)
|
||||
x60 := (x10 + x59)
|
||||
x61 := (x9 + x60)
|
||||
x62 := (x8 + x61)
|
||||
x63 := (x7 + x62)
|
||||
x64 := (x63 & 0x7ffffffffffff)
|
||||
x65 := u8((x63 >> 51))
|
||||
x66 := (x6 + u64(x65))
|
||||
x67 := (x5 + x66)
|
||||
x68 := (x4 + x67)
|
||||
x69 := (x3 + x68)
|
||||
x70 := (x2 + x69)
|
||||
x71 := (x1 + x70)
|
||||
out1[0] = x39
|
||||
out1[1] = x47
|
||||
out1[2] = x56
|
||||
out1[3] = x64
|
||||
out1[4] = x71
|
||||
}
|
||||
|
||||
fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
|
||||
x1 := arg1[0]
|
||||
x2 := arg1[1]
|
||||
x3 := arg1[2]
|
||||
x4 := arg1[3]
|
||||
x5 := arg1[4]
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_carry_scmul_121666 :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
|
||||
x2, x1 := bits.mul_u64(0x1db42, arg1[4])
|
||||
x4, x3 := bits.mul_u64(0x1db42, arg1[3])
|
||||
x6, x5 := bits.mul_u64(0x1db42, arg1[2])
|
||||
x8, x7 := bits.mul_u64(0x1db42, arg1[1])
|
||||
x10, x9 := bits.mul_u64(0x1db42, arg1[0])
|
||||
x11 := ((x9 >> 51) | ((x10 << 13) & 0xffffffffffffffff))
|
||||
x12 := (x9 & 0x7ffffffffffff)
|
||||
x13, x14 := bits.add_u64(x11, x7, u64(0x0))
|
||||
x15 := (u64(fiat.u1(x14)) + x8)
|
||||
x16 := ((x13 >> 51) | ((x15 << 13) & 0xffffffffffffffff))
|
||||
x17 := (x13 & 0x7ffffffffffff)
|
||||
x18, x19 := bits.add_u64(x16, x5, u64(0x0))
|
||||
x20 := (u64(fiat.u1(x19)) + x6)
|
||||
x21 := ((x18 >> 51) | ((x20 << 13) & 0xffffffffffffffff))
|
||||
x22 := (x18 & 0x7ffffffffffff)
|
||||
x23, x24 := bits.add_u64(x21, x3, u64(0x0))
|
||||
x25 := (u64(fiat.u1(x24)) + x4)
|
||||
x26 := ((x23 >> 51) | ((x25 << 13) & 0xffffffffffffffff))
|
||||
x27 := (x23 & 0x7ffffffffffff)
|
||||
x28, x29 := bits.add_u64(x26, x1, u64(0x0))
|
||||
x30 := (u64(fiat.u1(x29)) + x2)
|
||||
x31 := ((x28 >> 51) | ((x30 << 13) & 0xffffffffffffffff))
|
||||
x32 := (x28 & 0x7ffffffffffff)
|
||||
x33 := (x31 * 0x13)
|
||||
x34 := (x12 + x33)
|
||||
x35 := fiat.u1((x34 >> 51))
|
||||
x36 := (x34 & 0x7ffffffffffff)
|
||||
x37 := (u64(x35) + x17)
|
||||
x38 := fiat.u1((x37 >> 51))
|
||||
x39 := (x37 & 0x7ffffffffffff)
|
||||
x40 := (u64(x38) + x22)
|
||||
out1[0] = x36
|
||||
out1[1] = x39
|
||||
out1[2] = x40
|
||||
out1[3] = x27
|
||||
out1[4] = x32
|
||||
}
|
||||
|
||||
// The following routines were added by hand, and do not come from fiat-crypto.
|
||||
|
||||
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
|
||||
out1[0] = 0
|
||||
out1[1] = 0
|
||||
out1[2] = 0
|
||||
out1[3] = 0
|
||||
out1[4] = 0
|
||||
}
|
||||
|
||||
fe_one :: proc "contextless" (out1: ^Tight_Field_Element) {
|
||||
out1[0] = 1
|
||||
out1[1] = 0
|
||||
out1[2] = 0
|
||||
out1[3] = 0
|
||||
out1[4] = 0
|
||||
}
|
||||
|
||||
fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
x1 := arg1[0]
|
||||
x2 := arg1[1]
|
||||
x3 := arg1[2]
|
||||
x4 := arg1[3]
|
||||
x5 := arg1[4]
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) {
|
||||
mask := -u64(arg1)
|
||||
x := (out1[0] ~ out2[0]) & mask
|
||||
x1, y1 := out1[0] ~ x, out2[0] ~ x
|
||||
x = (out1[1] ~ out2[1]) & mask
|
||||
x2, y2 := out1[1] ~ x, out2[1] ~ x
|
||||
x = (out1[2] ~ out2[2]) & mask
|
||||
x3, y3 := out1[2] ~ x, out2[2] ~ x
|
||||
x = (out1[3] ~ out2[3]) & mask
|
||||
x4, y4 := out1[3] ~ x, out2[3] ~ x
|
||||
x = (out1[4] ~ out2[4]) & mask
|
||||
x5, y5 := out1[4] ~ x, out2[4] ~ x
|
||||
out1[0], out2[0] = x1, y1
|
||||
out1[1], out2[1] = x2, y2
|
||||
out1[2], out2[2] = x3, y3
|
||||
out1[3], out2[3] = x4, y4
|
||||
out1[4], out2[4] = x5, y5
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package field_poly1305
|
||||
|
||||
import "core:crypto/util"
|
||||
import "core:mem"
|
||||
|
||||
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element {
|
||||
return transmute(^Loose_Field_Element)(arg1)
|
||||
}
|
||||
|
||||
fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element {
|
||||
return transmute(^Tight_Field_Element)(arg1)
|
||||
}
|
||||
|
||||
fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte, sanitize: bool = true) {
|
||||
// fiat-crypto's deserialization routine effectively processes a
|
||||
// single byte at a time, and wants 256-bits of input for a value
|
||||
// that will be 128-bits or 129-bits.
|
||||
//
|
||||
// This is somewhat cumbersome to use, so at a minimum a wrapper
|
||||
// makes implementing the actual MAC block processing considerably
|
||||
// neater.
|
||||
|
||||
assert(len(arg1) == 16)
|
||||
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
// While it may be unwise to do deserialization here on our
|
||||
// own when fiat-crypto provides equivalent functionality,
|
||||
// doing it this way provides a little under 3x performance
|
||||
// improvement when optimization is enabled.
|
||||
src_p := transmute(^[2]u64)(&arg1[0])
|
||||
lo := src_p[0]
|
||||
hi := src_p[1]
|
||||
|
||||
// This is inspired by poly1305-donna, though adjustments were
|
||||
// made since a Tight_Field_Element's limbs are 44-bits, 43-bits,
|
||||
// and 43-bits wide.
|
||||
//
|
||||
// Note: This could be transplated into fe_from_u64s, but that
|
||||
// code is called once per MAC, and is non-criticial path.
|
||||
hibit := u64(arg2) << 41 // arg2 << 128
|
||||
out1[0] = lo & 0xfffffffffff
|
||||
out1[1] = ((lo >> 44) | (hi << 20)) & 0x7ffffffffff
|
||||
out1[2] = ((hi >> 23) & 0x7ffffffffff) | hibit
|
||||
} else {
|
||||
tmp: [32]byte
|
||||
copy_slice(tmp[0:16], arg1[:])
|
||||
tmp[16] = arg2
|
||||
|
||||
_fe_from_bytes(out1, &tmp)
|
||||
if sanitize {
|
||||
// This is used to deserialize `s` which is confidential.
|
||||
mem.zero_explicit(&tmp, size_of(tmp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fe_from_u64s :: proc "contextless" (out1: ^Tight_Field_Element, lo, hi: u64) {
|
||||
tmp: [32]byte
|
||||
util.PUT_U64_LE(tmp[0:8], lo)
|
||||
util.PUT_U64_LE(tmp[8:16], hi)
|
||||
|
||||
_fe_from_bytes(out1, &tmp)
|
||||
|
||||
// This routine is only used to deserialize `r` which is confidential.
|
||||
mem.zero_explicit(&tmp, size_of(tmp))
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
// The BSD 1-Clause License (BSD-1-Clause)
|
||||
//
|
||||
// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file)
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
|
||||
// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package field_poly1305
|
||||
|
||||
// This file provides arithmetic on the field Z/(2^130 - 5) using
|
||||
// unsaturated 64-bit integer arithmetic. It is derived primarily
|
||||
// from the machine generate Golang output from the fiat-crypto project.
|
||||
//
|
||||
// While the base implementation is provably correct, this implementation
|
||||
// makes no such claims as the port and optimizations were done by hand.
|
||||
// At some point, it may be worth adding support to fiat-crypto for
|
||||
// generating Odin output.
|
||||
|
||||
import fiat "core:crypto/_fiat"
|
||||
import "core:math/bits"
|
||||
|
||||
Loose_Field_Element :: distinct [3]u64
|
||||
Tight_Field_Element :: distinct [3]u64
|
||||
|
||||
_addcarryx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
|
||||
x1 := ((u64(arg1) + arg2) + arg3)
|
||||
x2 := (x1 & 0xfffffffffff)
|
||||
x3 := fiat.u1((x1 >> 44))
|
||||
out1 = x2
|
||||
out2 = x3
|
||||
return
|
||||
}
|
||||
|
||||
_subborrowx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
|
||||
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
|
||||
x2 := fiat.i1((x1 >> 44))
|
||||
x3 := (u64(x1) & 0xfffffffffff)
|
||||
out1 = x3
|
||||
out2 = (0x0 - fiat.u1(x2))
|
||||
return
|
||||
}
|
||||
|
||||
_addcarryx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
|
||||
x1 := ((u64(arg1) + arg2) + arg3)
|
||||
x2 := (x1 & 0x7ffffffffff)
|
||||
x3 := fiat.u1((x1 >> 43))
|
||||
out1 = x2
|
||||
out2 = x3
|
||||
return
|
||||
}
|
||||
|
||||
_subborrowx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
|
||||
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
|
||||
x2 := fiat.i1((x1 >> 43))
|
||||
x3 := (u64(x1) & 0x7ffffffffff)
|
||||
out1 = x3
|
||||
out2 = (0x0 - fiat.u1(x2))
|
||||
return
|
||||
}
|
||||
|
||||
fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) {
|
||||
x2, x1 := bits.mul_u64(arg1[2], (arg2[2] * 0x5))
|
||||
x4, x3 := bits.mul_u64(arg1[2], (arg2[1] * 0xa))
|
||||
x6, x5 := bits.mul_u64(arg1[1], (arg2[2] * 0xa))
|
||||
x8, x7 := bits.mul_u64(arg1[2], arg2[0])
|
||||
x10, x9 := bits.mul_u64(arg1[1], (arg2[1] * 0x2))
|
||||
x12, x11 := bits.mul_u64(arg1[1], arg2[0])
|
||||
x14, x13 := bits.mul_u64(arg1[0], arg2[2])
|
||||
x16, x15 := bits.mul_u64(arg1[0], arg2[1])
|
||||
x18, x17 := bits.mul_u64(arg1[0], arg2[0])
|
||||
x19, x20 := bits.add_u64(x5, x3, u64(0x0))
|
||||
x21, _ := bits.add_u64(x6, x4, u64(fiat.u1(x20)))
|
||||
x23, x24 := bits.add_u64(x17, x19, u64(0x0))
|
||||
x25, _ := bits.add_u64(x18, x21, u64(fiat.u1(x24)))
|
||||
x27 := ((x23 >> 44) | ((x25 << 20) & 0xffffffffffffffff))
|
||||
x28 := (x23 & 0xfffffffffff)
|
||||
x29, x30 := bits.add_u64(x9, x7, u64(0x0))
|
||||
x31, _ := bits.add_u64(x10, x8, u64(fiat.u1(x30)))
|
||||
x33, x34 := bits.add_u64(x13, x29, u64(0x0))
|
||||
x35, _ := bits.add_u64(x14, x31, u64(fiat.u1(x34)))
|
||||
x37, x38 := bits.add_u64(x11, x1, u64(0x0))
|
||||
x39, _ := bits.add_u64(x12, x2, u64(fiat.u1(x38)))
|
||||
x41, x42 := bits.add_u64(x15, x37, u64(0x0))
|
||||
x43, _ := bits.add_u64(x16, x39, u64(fiat.u1(x42)))
|
||||
x45, x46 := bits.add_u64(x27, x41, u64(0x0))
|
||||
x47 := (u64(fiat.u1(x46)) + x43)
|
||||
x48 := ((x45 >> 43) | ((x47 << 21) & 0xffffffffffffffff))
|
||||
x49 := (x45 & 0x7ffffffffff)
|
||||
x50, x51 := bits.add_u64(x48, x33, u64(0x0))
|
||||
x52 := (u64(fiat.u1(x51)) + x35)
|
||||
x53 := ((x50 >> 43) | ((x52 << 21) & 0xffffffffffffffff))
|
||||
x54 := (x50 & 0x7ffffffffff)
|
||||
x55 := (x53 * 0x5)
|
||||
x56 := (x28 + x55)
|
||||
x57 := (x56 >> 44)
|
||||
x58 := (x56 & 0xfffffffffff)
|
||||
x59 := (x57 + x49)
|
||||
x60 := fiat.u1((x59 >> 43))
|
||||
x61 := (x59 & 0x7ffffffffff)
|
||||
x62 := (u64(x60) + x54)
|
||||
out1[0] = x58
|
||||
out1[1] = x61
|
||||
out1[2] = x62
|
||||
}
|
||||
|
||||
fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
|
||||
x1 := (arg1[2] * 0x5)
|
||||
x2 := (x1 * 0x2)
|
||||
x3 := (arg1[2] * 0x2)
|
||||
x4 := (arg1[1] * 0x2)
|
||||
x6, x5 := bits.mul_u64(arg1[2], x1)
|
||||
x8, x7 := bits.mul_u64(arg1[1], (x2 * 0x2))
|
||||
x10, x9 := bits.mul_u64(arg1[1], (arg1[1] * 0x2))
|
||||
x12, x11 := bits.mul_u64(arg1[0], x3)
|
||||
x14, x13 := bits.mul_u64(arg1[0], x4)
|
||||
x16, x15 := bits.mul_u64(arg1[0], arg1[0])
|
||||
x17, x18 := bits.add_u64(x15, x7, u64(0x0))
|
||||
x19, _ := bits.add_u64(x16, x8, u64(fiat.u1(x18)))
|
||||
x21 := ((x17 >> 44) | ((x19 << 20) & 0xffffffffffffffff))
|
||||
x22 := (x17 & 0xfffffffffff)
|
||||
x23, x24 := bits.add_u64(x11, x9, u64(0x0))
|
||||
x25, _ := bits.add_u64(x12, x10, u64(fiat.u1(x24)))
|
||||
x27, x28 := bits.add_u64(x13, x5, u64(0x0))
|
||||
x29, _ := bits.add_u64(x14, x6, u64(fiat.u1(x28)))
|
||||
x31, x32 := bits.add_u64(x21, x27, u64(0x0))
|
||||
x33 := (u64(fiat.u1(x32)) + x29)
|
||||
x34 := ((x31 >> 43) | ((x33 << 21) & 0xffffffffffffffff))
|
||||
x35 := (x31 & 0x7ffffffffff)
|
||||
x36, x37 := bits.add_u64(x34, x23, u64(0x0))
|
||||
x38 := (u64(fiat.u1(x37)) + x25)
|
||||
x39 := ((x36 >> 43) | ((x38 << 21) & 0xffffffffffffffff))
|
||||
x40 := (x36 & 0x7ffffffffff)
|
||||
x41 := (x39 * 0x5)
|
||||
x42 := (x22 + x41)
|
||||
x43 := (x42 >> 44)
|
||||
x44 := (x42 & 0xfffffffffff)
|
||||
x45 := (x43 + x35)
|
||||
x46 := fiat.u1((x45 >> 43))
|
||||
x47 := (x45 & 0x7ffffffffff)
|
||||
x48 := (u64(x46) + x40)
|
||||
out1[0] = x44
|
||||
out1[1] = x47
|
||||
out1[2] = x48
|
||||
}
|
||||
|
||||
fe_carry :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
|
||||
x1 := arg1[0]
|
||||
x2 := ((x1 >> 44) + arg1[1])
|
||||
x3 := ((x2 >> 43) + arg1[2])
|
||||
x4 := ((x1 & 0xfffffffffff) + ((x3 >> 43) * 0x5))
|
||||
x5 := (u64(fiat.u1((x4 >> 44))) + (x2 & 0x7ffffffffff))
|
||||
x6 := (x4 & 0xfffffffffff)
|
||||
x7 := (x5 & 0x7ffffffffff)
|
||||
x8 := (u64(fiat.u1((x5 >> 43))) + (x3 & 0x7ffffffffff))
|
||||
out1[0] = x6
|
||||
out1[1] = x7
|
||||
out1[2] = x8
|
||||
}
|
||||
|
||||
fe_add :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
|
||||
x1 := (arg1[0] + arg2[0])
|
||||
x2 := (arg1[1] + arg2[1])
|
||||
x3 := (arg1[2] + arg2[2])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_sub :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
|
||||
x1 := ((0x1ffffffffff6 + arg1[0]) - arg2[0])
|
||||
x2 := ((0xffffffffffe + arg1[1]) - arg2[1])
|
||||
x3 := ((0xffffffffffe + arg1[2]) - arg2[2])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
|
||||
x1 := (0x1ffffffffff6 - arg1[0])
|
||||
x2 := (0xffffffffffe - arg1[1])
|
||||
x3 := (0xffffffffffe - arg1[2])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) {
|
||||
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
|
||||
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
|
||||
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_to_bytes :: proc "contextless" (out1: ^[32]byte, arg1: ^Tight_Field_Element) {
|
||||
x1, x2 := _subborrowx_u44(0x0, arg1[0], 0xffffffffffb)
|
||||
x3, x4 := _subborrowx_u43(x2, arg1[1], 0x7ffffffffff)
|
||||
x5, x6 := _subborrowx_u43(x4, arg1[2], 0x7ffffffffff)
|
||||
x7 := fiat.cmovznz_u64(x6, u64(0x0), 0xffffffffffffffff)
|
||||
x8, x9 := _addcarryx_u44(0x0, x1, (x7 & 0xffffffffffb))
|
||||
x10, x11 := _addcarryx_u43(x9, x3, (x7 & 0x7ffffffffff))
|
||||
x12, _ := _addcarryx_u43(x11, x5, (x7 & 0x7ffffffffff))
|
||||
x14 := (x12 << 7)
|
||||
x15 := (x10 << 4)
|
||||
x16 := (u8(x8) & 0xff)
|
||||
x17 := (x8 >> 8)
|
||||
x18 := (u8(x17) & 0xff)
|
||||
x19 := (x17 >> 8)
|
||||
x20 := (u8(x19) & 0xff)
|
||||
x21 := (x19 >> 8)
|
||||
x22 := (u8(x21) & 0xff)
|
||||
x23 := (x21 >> 8)
|
||||
x24 := (u8(x23) & 0xff)
|
||||
x25 := u8((x23 >> 8))
|
||||
x26 := (x15 + u64(x25))
|
||||
x27 := (u8(x26) & 0xff)
|
||||
x28 := (x26 >> 8)
|
||||
x29 := (u8(x28) & 0xff)
|
||||
x30 := (x28 >> 8)
|
||||
x31 := (u8(x30) & 0xff)
|
||||
x32 := (x30 >> 8)
|
||||
x33 := (u8(x32) & 0xff)
|
||||
x34 := (x32 >> 8)
|
||||
x35 := (u8(x34) & 0xff)
|
||||
x36 := u8((x34 >> 8))
|
||||
x37 := (x14 + u64(x36))
|
||||
x38 := (u8(x37) & 0xff)
|
||||
x39 := (x37 >> 8)
|
||||
x40 := (u8(x39) & 0xff)
|
||||
x41 := (x39 >> 8)
|
||||
x42 := (u8(x41) & 0xff)
|
||||
x43 := (x41 >> 8)
|
||||
x44 := (u8(x43) & 0xff)
|
||||
x45 := (x43 >> 8)
|
||||
x46 := (u8(x45) & 0xff)
|
||||
x47 := (x45 >> 8)
|
||||
x48 := (u8(x47) & 0xff)
|
||||
x49 := u8((x47 >> 8))
|
||||
out1[0] = x16
|
||||
out1[1] = x18
|
||||
out1[2] = x20
|
||||
out1[3] = x22
|
||||
out1[4] = x24
|
||||
out1[5] = x27
|
||||
out1[6] = x29
|
||||
out1[7] = x31
|
||||
out1[8] = x33
|
||||
out1[9] = x35
|
||||
out1[10] = x38
|
||||
out1[11] = x40
|
||||
out1[12] = x42
|
||||
out1[13] = x44
|
||||
out1[14] = x46
|
||||
out1[15] = x48
|
||||
out1[16] = x49
|
||||
}
|
||||
|
||||
_fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) {
|
||||
x1 := (u64(arg1[16]) << 41)
|
||||
x2 := (u64(arg1[15]) << 33)
|
||||
x3 := (u64(arg1[14]) << 25)
|
||||
x4 := (u64(arg1[13]) << 17)
|
||||
x5 := (u64(arg1[12]) << 9)
|
||||
x6 := (u64(arg1[11]) * u64(0x2))
|
||||
x7 := (u64(arg1[10]) << 36)
|
||||
x8 := (u64(arg1[9]) << 28)
|
||||
x9 := (u64(arg1[8]) << 20)
|
||||
x10 := (u64(arg1[7]) << 12)
|
||||
x11 := (u64(arg1[6]) << 4)
|
||||
x12 := (u64(arg1[5]) << 40)
|
||||
x13 := (u64(arg1[4]) << 32)
|
||||
x14 := (u64(arg1[3]) << 24)
|
||||
x15 := (u64(arg1[2]) << 16)
|
||||
x16 := (u64(arg1[1]) << 8)
|
||||
x17 := arg1[0]
|
||||
x18 := (x16 + u64(x17))
|
||||
x19 := (x15 + x18)
|
||||
x20 := (x14 + x19)
|
||||
x21 := (x13 + x20)
|
||||
x22 := (x12 + x21)
|
||||
x23 := (x22 & 0xfffffffffff)
|
||||
x24 := u8((x22 >> 44))
|
||||
x25 := (x11 + u64(x24))
|
||||
x26 := (x10 + x25)
|
||||
x27 := (x9 + x26)
|
||||
x28 := (x8 + x27)
|
||||
x29 := (x7 + x28)
|
||||
x30 := (x29 & 0x7ffffffffff)
|
||||
x31 := fiat.u1((x29 >> 43))
|
||||
x32 := (x6 + u64(x31))
|
||||
x33 := (x5 + x32)
|
||||
x34 := (x4 + x33)
|
||||
x35 := (x3 + x34)
|
||||
x36 := (x2 + x35)
|
||||
x37 := (x1 + x36)
|
||||
out1[0] = x23
|
||||
out1[1] = x30
|
||||
out1[2] = x37
|
||||
}
|
||||
|
||||
fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
|
||||
x1 := arg1[0]
|
||||
x2 := arg1[1]
|
||||
x3 := arg1[2]
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
// The following routines were added by hand, and do not come from fiat-crypto.
|
||||
|
||||
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
|
||||
out1[0] = 0
|
||||
out1[1] = 0
|
||||
out1[2] = 0
|
||||
}
|
||||
|
||||
fe_set :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
x1 := arg1[0]
|
||||
x2 := arg1[1]
|
||||
x3 := arg1[2]
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: bool) {
|
||||
mask := -u64(arg1)
|
||||
x := (out1[0] ~ out2[0]) & mask
|
||||
x1, y1 := out1[0] ~ x, out2[0] ~ x
|
||||
x = (out1[1] ~ out2[1]) & mask
|
||||
x2, y2 := out1[1] ~ x, out2[1] ~ x
|
||||
x = (out1[2] ~ out2[2]) & mask
|
||||
x3, y3 := out1[2] ~ x, out2[2] ~ x
|
||||
out1[0], out2[0] = x1, y1
|
||||
out1[1], out2[1] = x2, y2
|
||||
out1[2], out2[2] = x3, y3
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package _sha3
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the Keccak hashing algorithm, standardized as SHA3 in <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>
|
||||
To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding.
|
||||
*/
|
||||
|
||||
import "../util"
|
||||
|
||||
ROUNDS :: 24
|
||||
|
||||
Sha3_Context :: struct {
|
||||
st: struct #raw_union {
|
||||
b: [200]u8,
|
||||
q: [25]u64,
|
||||
},
|
||||
pt: int,
|
||||
rsiz: int,
|
||||
mdlen: int,
|
||||
is_keccak: bool,
|
||||
}
|
||||
|
||||
keccakf :: proc "contextless" (st: ^[25]u64) {
|
||||
keccakf_rndc := [?]u64 {
|
||||
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
|
||||
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
|
||||
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
|
||||
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
|
||||
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
|
||||
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
|
||||
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
||||
0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
|
||||
}
|
||||
|
||||
keccakf_rotc := [?]i32 {
|
||||
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
|
||||
}
|
||||
|
||||
keccakf_piln := [?]i32 {
|
||||
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
|
||||
}
|
||||
|
||||
i, j, r: i32 = ---, ---, ---
|
||||
t: u64 = ---
|
||||
bc: [5]u64 = ---
|
||||
|
||||
when ODIN_ENDIAN != .Little {
|
||||
v: uintptr = ---
|
||||
for i = 0; i < 25; i += 1 {
|
||||
v := uintptr(&st[i])
|
||||
st[i] = u64((^u8)(v + 0)^ << 0) | u64((^u8)(v + 1)^ << 8) |
|
||||
u64((^u8)(v + 2)^ << 16) | u64((^u8)(v + 3)^ << 24) |
|
||||
u64((^u8)(v + 4)^ << 32) | u64((^u8)(v + 5)^ << 40) |
|
||||
u64((^u8)(v + 6)^ << 48) | u64((^u8)(v + 7)^ << 56)
|
||||
}
|
||||
}
|
||||
|
||||
for r = 0; r < ROUNDS; r += 1 {
|
||||
// theta
|
||||
for i = 0; i < 5; i += 1 {
|
||||
bc[i] = st[i] ~ st[i + 5] ~ st[i + 10] ~ st[i + 15] ~ st[i + 20]
|
||||
}
|
||||
|
||||
for i = 0; i < 5; i += 1 {
|
||||
t = bc[(i + 4) % 5] ~ util.ROTL64(bc[(i + 1) % 5], 1)
|
||||
for j = 0; j < 25; j += 5 {
|
||||
st[j + i] ~= t
|
||||
}
|
||||
}
|
||||
|
||||
// rho pi
|
||||
t = st[1]
|
||||
for i = 0; i < 24; i += 1 {
|
||||
j = keccakf_piln[i]
|
||||
bc[0] = st[j]
|
||||
st[j] = util.ROTL64(t, u64(keccakf_rotc[i]))
|
||||
t = bc[0]
|
||||
}
|
||||
|
||||
// chi
|
||||
for j = 0; j < 25; j += 5 {
|
||||
for i = 0; i < 5; i += 1 {
|
||||
bc[i] = st[j + i]
|
||||
}
|
||||
for i = 0; i < 5; i += 1 {
|
||||
st[j + i] ~= ~bc[(i + 1) % 5] & bc[(i + 2) % 5]
|
||||
}
|
||||
}
|
||||
|
||||
st[0] ~= keccakf_rndc[r]
|
||||
}
|
||||
|
||||
when ODIN_ENDIAN != .Little {
|
||||
for i = 0; i < 25; i += 1 {
|
||||
v = uintptr(&st[i])
|
||||
t = st[i]
|
||||
(^u8)(v + 0)^ = (t >> 0) & 0xff
|
||||
(^u8)(v + 1)^ = (t >> 8) & 0xff
|
||||
(^u8)(v + 2)^ = (t >> 16) & 0xff
|
||||
(^u8)(v + 3)^ = (t >> 24) & 0xff
|
||||
(^u8)(v + 4)^ = (t >> 32) & 0xff
|
||||
(^u8)(v + 5)^ = (t >> 40) & 0xff
|
||||
(^u8)(v + 6)^ = (t >> 48) & 0xff
|
||||
(^u8)(v + 7)^ = (t >> 56) & 0xff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init :: proc "contextless" (c: ^Sha3_Context) {
|
||||
for i := 0; i < 25; i += 1 {
|
||||
c.st.q[i] = 0
|
||||
}
|
||||
c.rsiz = 200 - 2 * c.mdlen
|
||||
}
|
||||
|
||||
update :: proc "contextless" (c: ^Sha3_Context, data: []byte) {
|
||||
j := c.pt
|
||||
for i := 0; i < len(data); i += 1 {
|
||||
c.st.b[j] ~= data[i]
|
||||
j += 1
|
||||
if j >= c.rsiz {
|
||||
keccakf(&c.st.q)
|
||||
j = 0
|
||||
}
|
||||
}
|
||||
c.pt = j
|
||||
}
|
||||
|
||||
final :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
|
||||
if c.is_keccak {
|
||||
c.st.b[c.pt] ~= 0x01
|
||||
} else {
|
||||
c.st.b[c.pt] ~= 0x06
|
||||
}
|
||||
|
||||
c.st.b[c.rsiz - 1] ~= 0x80
|
||||
keccakf(&c.st.q)
|
||||
for i := 0; i < c.mdlen; i += 1 {
|
||||
hash[i] = c.st.b[i]
|
||||
}
|
||||
}
|
||||
|
||||
shake_xof :: proc "contextless" (c: ^Sha3_Context) {
|
||||
c.st.b[c.pt] ~= 0x1F
|
||||
c.st.b[c.rsiz - 1] ~= 0x80
|
||||
keccakf(&c.st.q)
|
||||
c.pt = 0
|
||||
}
|
||||
|
||||
shake_out :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
|
||||
j := c.pt
|
||||
for i := 0; i < len(hash); i += 1 {
|
||||
if j >= c.rsiz {
|
||||
keccakf(&c.st.q)
|
||||
j = 0
|
||||
}
|
||||
hash[i] = c.st.b[j]
|
||||
j += 1
|
||||
}
|
||||
c.pt = j
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
package _tiger
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the Tiger hashing algorithm, as defined in <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
|
||||
*/
|
||||
|
||||
import "../util"
|
||||
|
||||
T1 := [?]u64 {
|
||||
0x02aab17cf7e90c5e, 0xac424b03e243a8ec, 0x72cd5be30dd5fcd3, 0x6d019b93f6f97f3a,
|
||||
0xcd9978ffd21f9193, 0x7573a1c9708029e2, 0xb164326b922a83c3, 0x46883eee04915870,
|
||||
0xeaace3057103ece6, 0xc54169b808a3535c, 0x4ce754918ddec47c, 0x0aa2f4dfdc0df40c,
|
||||
0x10b76f18a74dbefa, 0xc6ccb6235ad1ab6a, 0x13726121572fe2ff, 0x1a488c6f199d921e,
|
||||
0x4bc9f9f4da0007ca, 0x26f5e6f6e85241c7, 0x859079dbea5947b6, 0x4f1885c5c99e8c92,
|
||||
0xd78e761ea96f864b, 0x8e36428c52b5c17d, 0x69cf6827373063c1, 0xb607c93d9bb4c56e,
|
||||
0x7d820e760e76b5ea, 0x645c9cc6f07fdc42, 0xbf38a078243342e0, 0x5f6b343c9d2e7d04,
|
||||
0xf2c28aeb600b0ec6, 0x6c0ed85f7254bcac, 0x71592281a4db4fe5, 0x1967fa69ce0fed9f,
|
||||
0xfd5293f8b96545db, 0xc879e9d7f2a7600b, 0x860248920193194e, 0xa4f9533b2d9cc0b3,
|
||||
0x9053836c15957613, 0xdb6dcf8afc357bf1, 0x18beea7a7a370f57, 0x037117ca50b99066,
|
||||
0x6ab30a9774424a35, 0xf4e92f02e325249b, 0x7739db07061ccae1, 0xd8f3b49ceca42a05,
|
||||
0xbd56be3f51382f73, 0x45faed5843b0bb28, 0x1c813d5c11bf1f83, 0x8af0e4b6d75fa169,
|
||||
0x33ee18a487ad9999, 0x3c26e8eab1c94410, 0xb510102bc0a822f9, 0x141eef310ce6123b,
|
||||
0xfc65b90059ddb154, 0xe0158640c5e0e607, 0x884e079826c3a3cf, 0x930d0d9523c535fd,
|
||||
0x35638d754e9a2b00, 0x4085fccf40469dd5, 0xc4b17ad28be23a4c, 0xcab2f0fc6a3e6a2e,
|
||||
0x2860971a6b943fcd, 0x3dde6ee212e30446, 0x6222f32ae01765ae, 0x5d550bb5478308fe,
|
||||
0xa9efa98da0eda22a, 0xc351a71686c40da7, 0x1105586d9c867c84, 0xdcffee85fda22853,
|
||||
0xccfbd0262c5eef76, 0xbaf294cb8990d201, 0xe69464f52afad975, 0x94b013afdf133e14,
|
||||
0x06a7d1a32823c958, 0x6f95fe5130f61119, 0xd92ab34e462c06c0, 0xed7bde33887c71d2,
|
||||
0x79746d6e6518393e, 0x5ba419385d713329, 0x7c1ba6b948a97564, 0x31987c197bfdac67,
|
||||
0xde6c23c44b053d02, 0x581c49fed002d64d, 0xdd474d6338261571, 0xaa4546c3e473d062,
|
||||
0x928fce349455f860, 0x48161bbacaab94d9, 0x63912430770e6f68, 0x6ec8a5e602c6641c,
|
||||
0x87282515337ddd2b, 0x2cda6b42034b701b, 0xb03d37c181cb096d, 0xe108438266c71c6f,
|
||||
0x2b3180c7eb51b255, 0xdf92b82f96c08bbc, 0x5c68c8c0a632f3ba, 0x5504cc861c3d0556,
|
||||
0xabbfa4e55fb26b8f, 0x41848b0ab3baceb4, 0xb334a273aa445d32, 0xbca696f0a85ad881,
|
||||
0x24f6ec65b528d56c, 0x0ce1512e90f4524a, 0x4e9dd79d5506d35a, 0x258905fac6ce9779,
|
||||
0x2019295b3e109b33, 0xf8a9478b73a054cc, 0x2924f2f934417eb0, 0x3993357d536d1bc4,
|
||||
0x38a81ac21db6ff8b, 0x47c4fbf17d6016bf, 0x1e0faadd7667e3f5, 0x7abcff62938beb96,
|
||||
0xa78dad948fc179c9, 0x8f1f98b72911e50d, 0x61e48eae27121a91, 0x4d62f7ad31859808,
|
||||
0xeceba345ef5ceaeb, 0xf5ceb25ebc9684ce, 0xf633e20cb7f76221, 0xa32cdf06ab8293e4,
|
||||
0x985a202ca5ee2ca4, 0xcf0b8447cc8a8fb1, 0x9f765244979859a3, 0xa8d516b1a1240017,
|
||||
0x0bd7ba3ebb5dc726, 0xe54bca55b86adb39, 0x1d7a3afd6c478063, 0x519ec608e7669edd,
|
||||
0x0e5715a2d149aa23, 0x177d4571848ff194, 0xeeb55f3241014c22, 0x0f5e5ca13a6e2ec2,
|
||||
0x8029927b75f5c361, 0xad139fabc3d6e436, 0x0d5df1a94ccf402f, 0x3e8bd948bea5dfc8,
|
||||
0xa5a0d357bd3ff77e, 0xa2d12e251f74f645, 0x66fd9e525e81a082, 0x2e0c90ce7f687a49,
|
||||
0xc2e8bcbeba973bc5, 0x000001bce509745f, 0x423777bbe6dab3d6, 0xd1661c7eaef06eb5,
|
||||
0xa1781f354daacfd8, 0x2d11284a2b16affc, 0xf1fc4f67fa891d1f, 0x73ecc25dcb920ada,
|
||||
0xae610c22c2a12651, 0x96e0a810d356b78a, 0x5a9a381f2fe7870f, 0xd5ad62ede94e5530,
|
||||
0xd225e5e8368d1427, 0x65977b70c7af4631, 0x99f889b2de39d74f, 0x233f30bf54e1d143,
|
||||
0x9a9675d3d9a63c97, 0x5470554ff334f9a8, 0x166acb744a4f5688, 0x70c74caab2e4aead,
|
||||
0xf0d091646f294d12, 0x57b82a89684031d1, 0xefd95a5a61be0b6b, 0x2fbd12e969f2f29a,
|
||||
0x9bd37013feff9fe8, 0x3f9b0404d6085a06, 0x4940c1f3166cfe15, 0x09542c4dcdf3defb,
|
||||
0xb4c5218385cd5ce3, 0xc935b7dc4462a641, 0x3417f8a68ed3b63f, 0xb80959295b215b40,
|
||||
0xf99cdaef3b8c8572, 0x018c0614f8fcb95d, 0x1b14accd1a3acdf3, 0x84d471f200bb732d,
|
||||
0xc1a3110e95e8da16, 0x430a7220bf1a82b8, 0xb77e090d39df210e, 0x5ef4bd9f3cd05e9d,
|
||||
0x9d4ff6da7e57a444, 0xda1d60e183d4a5f8, 0xb287c38417998e47, 0xfe3edc121bb31886,
|
||||
0xc7fe3ccc980ccbef, 0xe46fb590189bfd03, 0x3732fd469a4c57dc, 0x7ef700a07cf1ad65,
|
||||
0x59c64468a31d8859, 0x762fb0b4d45b61f6, 0x155baed099047718, 0x68755e4c3d50baa6,
|
||||
0xe9214e7f22d8b4df, 0x2addbf532eac95f4, 0x32ae3909b4bd0109, 0x834df537b08e3450,
|
||||
0xfa209da84220728d, 0x9e691d9b9efe23f7, 0x0446d288c4ae8d7f, 0x7b4cc524e169785b,
|
||||
0x21d87f0135ca1385, 0xcebb400f137b8aa5, 0x272e2b66580796be, 0x3612264125c2b0de,
|
||||
0x057702bdad1efbb2, 0xd4babb8eacf84be9, 0x91583139641bc67b, 0x8bdc2de08036e024,
|
||||
0x603c8156f49f68ed, 0xf7d236f7dbef5111, 0x9727c4598ad21e80, 0xa08a0896670a5fd7,
|
||||
0xcb4a8f4309eba9cb, 0x81af564b0f7036a1, 0xc0b99aa778199abd, 0x959f1ec83fc8e952,
|
||||
0x8c505077794a81b9, 0x3acaaf8f056338f0, 0x07b43f50627a6778, 0x4a44ab49f5eccc77,
|
||||
0x3bc3d6e4b679ee98, 0x9cc0d4d1cf14108c, 0x4406c00b206bc8a0, 0x82a18854c8d72d89,
|
||||
0x67e366b35c3c432c, 0xb923dd61102b37f2, 0x56ab2779d884271d, 0xbe83e1b0ff1525af,
|
||||
0xfb7c65d4217e49a9, 0x6bdbe0e76d48e7d4, 0x08df828745d9179e, 0x22ea6a9add53bd34,
|
||||
0xe36e141c5622200a, 0x7f805d1b8cb750ee, 0xafe5c7a59f58e837, 0xe27f996a4fb1c23c,
|
||||
0xd3867dfb0775f0d0, 0xd0e673de6e88891a, 0x123aeb9eafb86c25, 0x30f1d5d5c145b895,
|
||||
0xbb434a2dee7269e7, 0x78cb67ecf931fa38, 0xf33b0372323bbf9c, 0x52d66336fb279c74,
|
||||
0x505f33ac0afb4eaa, 0xe8a5cd99a2cce187, 0x534974801e2d30bb, 0x8d2d5711d5876d90,
|
||||
0x1f1a412891bc038e, 0xd6e2e71d82e56648, 0x74036c3a497732b7, 0x89b67ed96361f5ab,
|
||||
0xffed95d8f1ea02a2, 0xe72b3bd61464d43d, 0xa6300f170bdc4820, 0xebc18760ed78a77a,
|
||||
}
|
||||
|
||||
T2 := [?]u64 {
|
||||
0xe6a6be5a05a12138, 0xb5a122a5b4f87c98, 0x563c6089140b6990, 0x4c46cb2e391f5dd5,
|
||||
0xd932addbc9b79434, 0x08ea70e42015aff5, 0xd765a6673e478cf1, 0xc4fb757eab278d99,
|
||||
0xdf11c6862d6e0692, 0xddeb84f10d7f3b16, 0x6f2ef604a665ea04, 0x4a8e0f0ff0e0dfb3,
|
||||
0xa5edeef83dbcba51, 0xfc4f0a2a0ea4371e, 0xe83e1da85cb38429, 0xdc8ff882ba1b1ce2,
|
||||
0xcd45505e8353e80d, 0x18d19a00d4db0717, 0x34a0cfeda5f38101, 0x0be77e518887caf2,
|
||||
0x1e341438b3c45136, 0xe05797f49089ccf9, 0xffd23f9df2591d14, 0x543dda228595c5cd,
|
||||
0x661f81fd99052a33, 0x8736e641db0f7b76, 0x15227725418e5307, 0xe25f7f46162eb2fa,
|
||||
0x48a8b2126c13d9fe, 0xafdc541792e76eea, 0x03d912bfc6d1898f, 0x31b1aafa1b83f51b,
|
||||
0xf1ac2796e42ab7d9, 0x40a3a7d7fcd2ebac, 0x1056136d0afbbcc5, 0x7889e1dd9a6d0c85,
|
||||
0xd33525782a7974aa, 0xa7e25d09078ac09b, 0xbd4138b3eac6edd0, 0x920abfbe71eb9e70,
|
||||
0xa2a5d0f54fc2625c, 0xc054e36b0b1290a3, 0xf6dd59ff62fe932b, 0x3537354511a8ac7d,
|
||||
0xca845e9172fadcd4, 0x84f82b60329d20dc, 0x79c62ce1cd672f18, 0x8b09a2add124642c,
|
||||
0xd0c1e96a19d9e726, 0x5a786a9b4ba9500c, 0x0e020336634c43f3, 0xc17b474aeb66d822,
|
||||
0x6a731ae3ec9baac2, 0x8226667ae0840258, 0x67d4567691caeca5, 0x1d94155c4875adb5,
|
||||
0x6d00fd985b813fdf, 0x51286efcb774cd06, 0x5e8834471fa744af, 0xf72ca0aee761ae2e,
|
||||
0xbe40e4cdaee8e09a, 0xe9970bbb5118f665, 0x726e4beb33df1964, 0x703b000729199762,
|
||||
0x4631d816f5ef30a7, 0xb880b5b51504a6be, 0x641793c37ed84b6c, 0x7b21ed77f6e97d96,
|
||||
0x776306312ef96b73, 0xae528948e86ff3f4, 0x53dbd7f286a3f8f8, 0x16cadce74cfc1063,
|
||||
0x005c19bdfa52c6dd, 0x68868f5d64d46ad3, 0x3a9d512ccf1e186a, 0x367e62c2385660ae,
|
||||
0xe359e7ea77dcb1d7, 0x526c0773749abe6e, 0x735ae5f9d09f734b, 0x493fc7cc8a558ba8,
|
||||
0xb0b9c1533041ab45, 0x321958ba470a59bd, 0x852db00b5f46c393, 0x91209b2bd336b0e5,
|
||||
0x6e604f7d659ef19f, 0xb99a8ae2782ccb24, 0xccf52ab6c814c4c7, 0x4727d9afbe11727b,
|
||||
0x7e950d0c0121b34d, 0x756f435670ad471f, 0xf5add442615a6849, 0x4e87e09980b9957a,
|
||||
0x2acfa1df50aee355, 0xd898263afd2fd556, 0xc8f4924dd80c8fd6, 0xcf99ca3d754a173a,
|
||||
0xfe477bacaf91bf3c, 0xed5371f6d690c12d, 0x831a5c285e687094, 0xc5d3c90a3708a0a4,
|
||||
0x0f7f903717d06580, 0x19f9bb13b8fdf27f, 0xb1bd6f1b4d502843, 0x1c761ba38fff4012,
|
||||
0x0d1530c4e2e21f3b, 0x8943ce69a7372c8a, 0xe5184e11feb5ce66, 0x618bdb80bd736621,
|
||||
0x7d29bad68b574d0b, 0x81bb613e25e6fe5b, 0x071c9c10bc07913f, 0xc7beeb7909ac2d97,
|
||||
0xc3e58d353bc5d757, 0xeb017892f38f61e8, 0xd4effb9c9b1cc21a, 0x99727d26f494f7ab,
|
||||
0xa3e063a2956b3e03, 0x9d4a8b9a4aa09c30, 0x3f6ab7d500090fb4, 0x9cc0f2a057268ac0,
|
||||
0x3dee9d2dedbf42d1, 0x330f49c87960a972, 0xc6b2720287421b41, 0x0ac59ec07c00369c,
|
||||
0xef4eac49cb353425, 0xf450244eef0129d8, 0x8acc46e5caf4deb6, 0x2ffeab63989263f7,
|
||||
0x8f7cb9fe5d7a4578, 0x5bd8f7644e634635, 0x427a7315bf2dc900, 0x17d0c4aa2125261c,
|
||||
0x3992486c93518e50, 0xb4cbfee0a2d7d4c3, 0x7c75d6202c5ddd8d, 0xdbc295d8e35b6c61,
|
||||
0x60b369d302032b19, 0xce42685fdce44132, 0x06f3ddb9ddf65610, 0x8ea4d21db5e148f0,
|
||||
0x20b0fce62fcd496f, 0x2c1b912358b0ee31, 0xb28317b818f5a308, 0xa89c1e189ca6d2cf,
|
||||
0x0c6b18576aaadbc8, 0xb65deaa91299fae3, 0xfb2b794b7f1027e7, 0x04e4317f443b5beb,
|
||||
0x4b852d325939d0a6, 0xd5ae6beefb207ffc, 0x309682b281c7d374, 0xbae309a194c3b475,
|
||||
0x8cc3f97b13b49f05, 0x98a9422ff8293967, 0x244b16b01076ff7c, 0xf8bf571c663d67ee,
|
||||
0x1f0d6758eee30da1, 0xc9b611d97adeb9b7, 0xb7afd5887b6c57a2, 0x6290ae846b984fe1,
|
||||
0x94df4cdeacc1a5fd, 0x058a5bd1c5483aff, 0x63166cc142ba3c37, 0x8db8526eb2f76f40,
|
||||
0xe10880036f0d6d4e, 0x9e0523c9971d311d, 0x45ec2824cc7cd691, 0x575b8359e62382c9,
|
||||
0xfa9e400dc4889995, 0xd1823ecb45721568, 0xdafd983b8206082f, 0xaa7d29082386a8cb,
|
||||
0x269fcd4403b87588, 0x1b91f5f728bdd1e0, 0xe4669f39040201f6, 0x7a1d7c218cf04ade,
|
||||
0x65623c29d79ce5ce, 0x2368449096c00bb1, 0xab9bf1879da503ba, 0xbc23ecb1a458058e,
|
||||
0x9a58df01bb401ecc, 0xa070e868a85f143d, 0x4ff188307df2239e, 0x14d565b41a641183,
|
||||
0xee13337452701602, 0x950e3dcf3f285e09, 0x59930254b9c80953, 0x3bf299408930da6d,
|
||||
0xa955943f53691387, 0xa15edecaa9cb8784, 0x29142127352be9a0, 0x76f0371fff4e7afb,
|
||||
0x0239f450274f2228, 0xbb073af01d5e868b, 0xbfc80571c10e96c1, 0xd267088568222e23,
|
||||
0x9671a3d48e80b5b0, 0x55b5d38ae193bb81, 0x693ae2d0a18b04b8, 0x5c48b4ecadd5335f,
|
||||
0xfd743b194916a1ca, 0x2577018134be98c4, 0xe77987e83c54a4ad, 0x28e11014da33e1b9,
|
||||
0x270cc59e226aa213, 0x71495f756d1a5f60, 0x9be853fb60afef77, 0xadc786a7f7443dbf,
|
||||
0x0904456173b29a82, 0x58bc7a66c232bd5e, 0xf306558c673ac8b2, 0x41f639c6b6c9772a,
|
||||
0x216defe99fda35da, 0x11640cc71c7be615, 0x93c43694565c5527, 0xea038e6246777839,
|
||||
0xf9abf3ce5a3e2469, 0x741e768d0fd312d2, 0x0144b883ced652c6, 0xc20b5a5ba33f8552,
|
||||
0x1ae69633c3435a9d, 0x97a28ca4088cfdec, 0x8824a43c1e96f420, 0x37612fa66eeea746,
|
||||
0x6b4cb165f9cf0e5a, 0x43aa1c06a0abfb4a, 0x7f4dc26ff162796b, 0x6cbacc8e54ed9b0f,
|
||||
0xa6b7ffefd2bb253e, 0x2e25bc95b0a29d4f, 0x86d6a58bdef1388c, 0xded74ac576b6f054,
|
||||
0x8030bdbc2b45805d, 0x3c81af70e94d9289, 0x3eff6dda9e3100db, 0xb38dc39fdfcc8847,
|
||||
0x123885528d17b87e, 0xf2da0ed240b1b642, 0x44cefadcd54bf9a9, 0x1312200e433c7ee6,
|
||||
0x9ffcc84f3a78c748, 0xf0cd1f72248576bb, 0xec6974053638cfe4, 0x2ba7b67c0cec4e4c,
|
||||
0xac2f4df3e5ce32ed, 0xcb33d14326ea4c11, 0xa4e9044cc77e58bc, 0x5f513293d934fcef,
|
||||
0x5dc9645506e55444, 0x50de418f317de40a, 0x388cb31a69dde259, 0x2db4a83455820a86,
|
||||
0x9010a91e84711ae9, 0x4df7f0b7b1498371, 0xd62a2eabc0977179, 0x22fac097aa8d5c0e,
|
||||
}
|
||||
|
||||
T3 := [?]u64 {
|
||||
0xf49fcc2ff1daf39b, 0x487fd5c66ff29281, 0xe8a30667fcdca83f, 0x2c9b4be3d2fcce63,
|
||||
0xda3ff74b93fbbbc2, 0x2fa165d2fe70ba66, 0xa103e279970e93d4, 0xbecdec77b0e45e71,
|
||||
0xcfb41e723985e497, 0xb70aaa025ef75017, 0xd42309f03840b8e0, 0x8efc1ad035898579,
|
||||
0x96c6920be2b2abc5, 0x66af4163375a9172, 0x2174abdcca7127fb, 0xb33ccea64a72ff41,
|
||||
0xf04a4933083066a5, 0x8d970acdd7289af5, 0x8f96e8e031c8c25e, 0xf3fec02276875d47,
|
||||
0xec7bf310056190dd, 0xf5adb0aebb0f1491, 0x9b50f8850fd58892, 0x4975488358b74de8,
|
||||
0xa3354ff691531c61, 0x0702bbe481d2c6ee, 0x89fb24057deded98, 0xac3075138596e902,
|
||||
0x1d2d3580172772ed, 0xeb738fc28e6bc30d, 0x5854ef8f63044326, 0x9e5c52325add3bbe,
|
||||
0x90aa53cf325c4623, 0xc1d24d51349dd067, 0x2051cfeea69ea624, 0x13220f0a862e7e4f,
|
||||
0xce39399404e04864, 0xd9c42ca47086fcb7, 0x685ad2238a03e7cc, 0x066484b2ab2ff1db,
|
||||
0xfe9d5d70efbf79ec, 0x5b13b9dd9c481854, 0x15f0d475ed1509ad, 0x0bebcd060ec79851,
|
||||
0xd58c6791183ab7f8, 0xd1187c5052f3eee4, 0xc95d1192e54e82ff, 0x86eea14cb9ac6ca2,
|
||||
0x3485beb153677d5d, 0xdd191d781f8c492a, 0xf60866baa784ebf9, 0x518f643ba2d08c74,
|
||||
0x8852e956e1087c22, 0xa768cb8dc410ae8d, 0x38047726bfec8e1a, 0xa67738b4cd3b45aa,
|
||||
0xad16691cec0dde19, 0xc6d4319380462e07, 0xc5a5876d0ba61938, 0x16b9fa1fa58fd840,
|
||||
0x188ab1173ca74f18, 0xabda2f98c99c021f, 0x3e0580ab134ae816, 0x5f3b05b773645abb,
|
||||
0x2501a2be5575f2f6, 0x1b2f74004e7e8ba9, 0x1cd7580371e8d953, 0x7f6ed89562764e30,
|
||||
0xb15926ff596f003d, 0x9f65293da8c5d6b9, 0x6ecef04dd690f84c, 0x4782275fff33af88,
|
||||
0xe41433083f820801, 0xfd0dfe409a1af9b5, 0x4325a3342cdb396b, 0x8ae77e62b301b252,
|
||||
0xc36f9e9f6655615a, 0x85455a2d92d32c09, 0xf2c7dea949477485, 0x63cfb4c133a39eba,
|
||||
0x83b040cc6ebc5462, 0x3b9454c8fdb326b0, 0x56f56a9e87ffd78c, 0x2dc2940d99f42bc6,
|
||||
0x98f7df096b096e2d, 0x19a6e01e3ad852bf, 0x42a99ccbdbd4b40b, 0xa59998af45e9c559,
|
||||
0x366295e807d93186, 0x6b48181bfaa1f773, 0x1fec57e2157a0a1d, 0x4667446af6201ad5,
|
||||
0xe615ebcacfb0f075, 0xb8f31f4f68290778, 0x22713ed6ce22d11e, 0x3057c1a72ec3c93b,
|
||||
0xcb46acc37c3f1f2f, 0xdbb893fd02aaf50e, 0x331fd92e600b9fcf, 0xa498f96148ea3ad6,
|
||||
0xa8d8426e8b6a83ea, 0xa089b274b7735cdc, 0x87f6b3731e524a11, 0x118808e5cbc96749,
|
||||
0x9906e4c7b19bd394, 0xafed7f7e9b24a20c, 0x6509eadeeb3644a7, 0x6c1ef1d3e8ef0ede,
|
||||
0xb9c97d43e9798fb4, 0xa2f2d784740c28a3, 0x7b8496476197566f, 0x7a5be3e6b65f069d,
|
||||
0xf96330ed78be6f10, 0xeee60de77a076a15, 0x2b4bee4aa08b9bd0, 0x6a56a63ec7b8894e,
|
||||
0x02121359ba34fef4, 0x4cbf99f8283703fc, 0x398071350caf30c8, 0xd0a77a89f017687a,
|
||||
0xf1c1a9eb9e423569, 0x8c7976282dee8199, 0x5d1737a5dd1f7abd, 0x4f53433c09a9fa80,
|
||||
0xfa8b0c53df7ca1d9, 0x3fd9dcbc886ccb77, 0xc040917ca91b4720, 0x7dd00142f9d1dcdf,
|
||||
0x8476fc1d4f387b58, 0x23f8e7c5f3316503, 0x032a2244e7e37339, 0x5c87a5d750f5a74b,
|
||||
0x082b4cc43698992e, 0xdf917becb858f63c, 0x3270b8fc5bf86dda, 0x10ae72bb29b5dd76,
|
||||
0x576ac94e7700362b, 0x1ad112dac61efb8f, 0x691bc30ec5faa427, 0xff246311cc327143,
|
||||
0x3142368e30e53206, 0x71380e31e02ca396, 0x958d5c960aad76f1, 0xf8d6f430c16da536,
|
||||
0xc8ffd13f1be7e1d2, 0x7578ae66004ddbe1, 0x05833f01067be646, 0xbb34b5ad3bfe586d,
|
||||
0x095f34c9a12b97f0, 0x247ab64525d60ca8, 0xdcdbc6f3017477d1, 0x4a2e14d4decad24d,
|
||||
0xbdb5e6d9be0a1eeb, 0x2a7e70f7794301ab, 0xdef42d8a270540fd, 0x01078ec0a34c22c1,
|
||||
0xe5de511af4c16387, 0x7ebb3a52bd9a330a, 0x77697857aa7d6435, 0x004e831603ae4c32,
|
||||
0xe7a21020ad78e312, 0x9d41a70c6ab420f2, 0x28e06c18ea1141e6, 0xd2b28cbd984f6b28,
|
||||
0x26b75f6c446e9d83, 0xba47568c4d418d7f, 0xd80badbfe6183d8e, 0x0e206d7f5f166044,
|
||||
0xe258a43911cbca3e, 0x723a1746b21dc0bc, 0xc7caa854f5d7cdd3, 0x7cac32883d261d9c,
|
||||
0x7690c26423ba942c, 0x17e55524478042b8, 0xe0be477656a2389f, 0x4d289b5e67ab2da0,
|
||||
0x44862b9c8fbbfd31, 0xb47cc8049d141365, 0x822c1b362b91c793, 0x4eb14655fb13dfd8,
|
||||
0x1ecbba0714e2a97b, 0x6143459d5cde5f14, 0x53a8fbf1d5f0ac89, 0x97ea04d81c5e5b00,
|
||||
0x622181a8d4fdb3f3, 0xe9bcd341572a1208, 0x1411258643cce58a, 0x9144c5fea4c6e0a4,
|
||||
0x0d33d06565cf620f, 0x54a48d489f219ca1, 0xc43e5eac6d63c821, 0xa9728b3a72770daf,
|
||||
0xd7934e7b20df87ef, 0xe35503b61a3e86e5, 0xcae321fbc819d504, 0x129a50b3ac60bfa6,
|
||||
0xcd5e68ea7e9fb6c3, 0xb01c90199483b1c7, 0x3de93cd5c295376c, 0xaed52edf2ab9ad13,
|
||||
0x2e60f512c0a07884, 0xbc3d86a3e36210c9, 0x35269d9b163951ce, 0x0c7d6e2ad0cdb5fa,
|
||||
0x59e86297d87f5733, 0x298ef221898db0e7, 0x55000029d1a5aa7e, 0x8bc08ae1b5061b45,
|
||||
0xc2c31c2b6c92703a, 0x94cc596baf25ef42, 0x0a1d73db22540456, 0x04b6a0f9d9c4179a,
|
||||
0xeffdafa2ae3d3c60, 0xf7c8075bb49496c4, 0x9cc5c7141d1cd4e3, 0x78bd1638218e5534,
|
||||
0xb2f11568f850246a, 0xedfabcfa9502bc29, 0x796ce5f2da23051b, 0xaae128b0dc93537c,
|
||||
0x3a493da0ee4b29ae, 0xb5df6b2c416895d7, 0xfcabbd25122d7f37, 0x70810b58105dc4b1,
|
||||
0xe10fdd37f7882a90, 0x524dcab5518a3f5c, 0x3c9e85878451255b, 0x4029828119bd34e2,
|
||||
0x74a05b6f5d3ceccb, 0xb610021542e13eca, 0x0ff979d12f59e2ac, 0x6037da27e4f9cc50,
|
||||
0x5e92975a0df1847d, 0xd66de190d3e623fe, 0x5032d6b87b568048, 0x9a36b7ce8235216e,
|
||||
0x80272a7a24f64b4a, 0x93efed8b8c6916f7, 0x37ddbff44cce1555, 0x4b95db5d4b99bd25,
|
||||
0x92d3fda169812fc0, 0xfb1a4a9a90660bb6, 0x730c196946a4b9b2, 0x81e289aa7f49da68,
|
||||
0x64669a0f83b1a05f, 0x27b3ff7d9644f48b, 0xcc6b615c8db675b3, 0x674f20b9bcebbe95,
|
||||
0x6f31238275655982, 0x5ae488713e45cf05, 0xbf619f9954c21157, 0xeabac46040a8eae9,
|
||||
0x454c6fe9f2c0c1cd, 0x419cf6496412691c, 0xd3dc3bef265b0f70, 0x6d0e60f5c3578a9e,
|
||||
}
|
||||
|
||||
T4 := [?]u64 {
|
||||
0x5b0e608526323c55, 0x1a46c1a9fa1b59f5, 0xa9e245a17c4c8ffa, 0x65ca5159db2955d7,
|
||||
0x05db0a76ce35afc2, 0x81eac77ea9113d45, 0x528ef88ab6ac0a0d, 0xa09ea253597be3ff,
|
||||
0x430ddfb3ac48cd56, 0xc4b3a67af45ce46f, 0x4ececfd8fbe2d05e, 0x3ef56f10b39935f0,
|
||||
0x0b22d6829cd619c6, 0x17fd460a74df2069, 0x6cf8cc8e8510ed40, 0xd6c824bf3a6ecaa7,
|
||||
0x61243d581a817049, 0x048bacb6bbc163a2, 0xd9a38ac27d44cc32, 0x7fddff5baaf410ab,
|
||||
0xad6d495aa804824b, 0xe1a6a74f2d8c9f94, 0xd4f7851235dee8e3, 0xfd4b7f886540d893,
|
||||
0x247c20042aa4bfda, 0x096ea1c517d1327c, 0xd56966b4361a6685, 0x277da5c31221057d,
|
||||
0x94d59893a43acff7, 0x64f0c51ccdc02281, 0x3d33bcc4ff6189db, 0xe005cb184ce66af1,
|
||||
0xff5ccd1d1db99bea, 0xb0b854a7fe42980f, 0x7bd46a6a718d4b9f, 0xd10fa8cc22a5fd8c,
|
||||
0xd31484952be4bd31, 0xc7fa975fcb243847, 0x4886ed1e5846c407, 0x28cddb791eb70b04,
|
||||
0xc2b00be2f573417f, 0x5c9590452180f877, 0x7a6bddfff370eb00, 0xce509e38d6d9d6a4,
|
||||
0xebeb0f00647fa702, 0x1dcc06cf76606f06, 0xe4d9f28ba286ff0a, 0xd85a305dc918c262,
|
||||
0x475b1d8732225f54, 0x2d4fb51668ccb5fe, 0xa679b9d9d72bba20, 0x53841c0d912d43a5,
|
||||
0x3b7eaa48bf12a4e8, 0x781e0e47f22f1ddf, 0xeff20ce60ab50973, 0x20d261d19dffb742,
|
||||
0x16a12b03062a2e39, 0x1960eb2239650495, 0x251c16fed50eb8b8, 0x9ac0c330f826016e,
|
||||
0xed152665953e7671, 0x02d63194a6369570, 0x5074f08394b1c987, 0x70ba598c90b25ce1,
|
||||
0x794a15810b9742f6, 0x0d5925e9fcaf8c6c, 0x3067716cd868744e, 0x910ab077e8d7731b,
|
||||
0x6a61bbdb5ac42f61, 0x93513efbf0851567, 0xf494724b9e83e9d5, 0xe887e1985c09648d,
|
||||
0x34b1d3c675370cfd, 0xdc35e433bc0d255d, 0xd0aab84234131be0, 0x08042a50b48b7eaf,
|
||||
0x9997c4ee44a3ab35, 0x829a7b49201799d0, 0x263b8307b7c54441, 0x752f95f4fd6a6ca6,
|
||||
0x927217402c08c6e5, 0x2a8ab754a795d9ee, 0xa442f7552f72943d, 0x2c31334e19781208,
|
||||
0x4fa98d7ceaee6291, 0x55c3862f665db309, 0xbd0610175d53b1f3, 0x46fe6cb840413f27,
|
||||
0x3fe03792df0cfa59, 0xcfe700372eb85e8f, 0xa7be29e7adbce118, 0xe544ee5cde8431dd,
|
||||
0x8a781b1b41f1873e, 0xa5c94c78a0d2f0e7, 0x39412e2877b60728, 0xa1265ef3afc9a62c,
|
||||
0xbcc2770c6a2506c5, 0x3ab66dd5dce1ce12, 0xe65499d04a675b37, 0x7d8f523481bfd216,
|
||||
0x0f6f64fcec15f389, 0x74efbe618b5b13c8, 0xacdc82b714273e1d, 0xdd40bfe003199d17,
|
||||
0x37e99257e7e061f8, 0xfa52626904775aaa, 0x8bbbf63a463d56f9, 0xf0013f1543a26e64,
|
||||
0xa8307e9f879ec898, 0xcc4c27a4150177cc, 0x1b432f2cca1d3348, 0xde1d1f8f9f6fa013,
|
||||
0x606602a047a7ddd6, 0xd237ab64cc1cb2c7, 0x9b938e7225fcd1d3, 0xec4e03708e0ff476,
|
||||
0xfeb2fbda3d03c12d, 0xae0bced2ee43889a, 0x22cb8923ebfb4f43, 0x69360d013cf7396d,
|
||||
0x855e3602d2d4e022, 0x073805bad01f784c, 0x33e17a133852f546, 0xdf4874058ac7b638,
|
||||
0xba92b29c678aa14a, 0x0ce89fc76cfaadcd, 0x5f9d4e0908339e34, 0xf1afe9291f5923b9,
|
||||
0x6e3480f60f4a265f, 0xeebf3a2ab29b841c, 0xe21938a88f91b4ad, 0x57dfeff845c6d3c3,
|
||||
0x2f006b0bf62caaf2, 0x62f479ef6f75ee78, 0x11a55ad41c8916a9, 0xf229d29084fed453,
|
||||
0x42f1c27b16b000e6, 0x2b1f76749823c074, 0x4b76eca3c2745360, 0x8c98f463b91691bd,
|
||||
0x14bcc93cf1ade66a, 0x8885213e6d458397, 0x8e177df0274d4711, 0xb49b73b5503f2951,
|
||||
0x10168168c3f96b6b, 0x0e3d963b63cab0ae, 0x8dfc4b5655a1db14, 0xf789f1356e14de5c,
|
||||
0x683e68af4e51dac1, 0xc9a84f9d8d4b0fd9, 0x3691e03f52a0f9d1, 0x5ed86e46e1878e80,
|
||||
0x3c711a0e99d07150, 0x5a0865b20c4e9310, 0x56fbfc1fe4f0682e, 0xea8d5de3105edf9b,
|
||||
0x71abfdb12379187a, 0x2eb99de1bee77b9c, 0x21ecc0ea33cf4523, 0x59a4d7521805c7a1,
|
||||
0x3896f5eb56ae7c72, 0xaa638f3db18f75dc, 0x9f39358dabe9808e, 0xb7defa91c00b72ac,
|
||||
0x6b5541fd62492d92, 0x6dc6dee8f92e4d5b, 0x353f57abc4beea7e, 0x735769d6da5690ce,
|
||||
0x0a234aa642391484, 0xf6f9508028f80d9d, 0xb8e319a27ab3f215, 0x31ad9c1151341a4d,
|
||||
0x773c22a57bef5805, 0x45c7561a07968633, 0xf913da9e249dbe36, 0xda652d9b78a64c68,
|
||||
0x4c27a97f3bc334ef, 0x76621220e66b17f4, 0x967743899acd7d0b, 0xf3ee5bcae0ed6782,
|
||||
0x409f753600c879fc, 0x06d09a39b5926db6, 0x6f83aeb0317ac588, 0x01e6ca4a86381f21,
|
||||
0x66ff3462d19f3025, 0x72207c24ddfd3bfb, 0x4af6b6d3e2ece2eb, 0x9c994dbec7ea08de,
|
||||
0x49ace597b09a8bc4, 0xb38c4766cf0797ba, 0x131b9373c57c2a75, 0xb1822cce61931e58,
|
||||
0x9d7555b909ba1c0c, 0x127fafdd937d11d2, 0x29da3badc66d92e4, 0xa2c1d57154c2ecbc,
|
||||
0x58c5134d82f6fe24, 0x1c3ae3515b62274f, 0xe907c82e01cb8126, 0xf8ed091913e37fcb,
|
||||
0x3249d8f9c80046c9, 0x80cf9bede388fb63, 0x1881539a116cf19e, 0x5103f3f76bd52457,
|
||||
0x15b7e6f5ae47f7a8, 0xdbd7c6ded47e9ccf, 0x44e55c410228bb1a, 0xb647d4255edb4e99,
|
||||
0x5d11882bb8aafc30, 0xf5098bbb29d3212a, 0x8fb5ea14e90296b3, 0x677b942157dd025a,
|
||||
0xfb58e7c0a390acb5, 0x89d3674c83bd4a01, 0x9e2da4df4bf3b93b, 0xfcc41e328cab4829,
|
||||
0x03f38c96ba582c52, 0xcad1bdbd7fd85db2, 0xbbb442c16082ae83, 0xb95fe86ba5da9ab0,
|
||||
0xb22e04673771a93f, 0x845358c9493152d8, 0xbe2a488697b4541e, 0x95a2dc2dd38e6966,
|
||||
0xc02c11ac923c852b, 0x2388b1990df2a87b, 0x7c8008fa1b4f37be, 0x1f70d0c84d54e503,
|
||||
0x5490adec7ece57d4, 0x002b3c27d9063a3a, 0x7eaea3848030a2bf, 0xc602326ded2003c0,
|
||||
0x83a7287d69a94086, 0xc57a5fcb30f57a8a, 0xb56844e479ebe779, 0xa373b40f05dcbce9,
|
||||
0xd71a786e88570ee2, 0x879cbacdbde8f6a0, 0x976ad1bcc164a32f, 0xab21e25e9666d78b,
|
||||
0x901063aae5e5c33c, 0x9818b34448698d90, 0xe36487ae3e1e8abb, 0xafbdf931893bdcb4,
|
||||
0x6345a0dc5fbbd519, 0x8628fe269b9465ca, 0x1e5d01603f9c51ec, 0x4de44006a15049b7,
|
||||
0xbf6c70e5f776cbb1, 0x411218f2ef552bed, 0xcb0c0708705a36a3, 0xe74d14754f986044,
|
||||
0xcd56d9430ea8280e, 0xc12591d7535f5065, 0xc83223f1720aef96, 0xc3a0396f7363a51f,
|
||||
}
|
||||
|
||||
Tiger_Context :: struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
x: [64]byte,
|
||||
nx: int,
|
||||
length: u64,
|
||||
ver: int,
|
||||
}
|
||||
|
||||
round :: #force_inline proc "contextless" (a, b, c, x, mul: u64) -> (u64, u64, u64) {
|
||||
a, b, c := a, b, c
|
||||
c ~= x
|
||||
a -= T1[c & 0xff] ~ T2[(c >> 16) & 0xff] ~ T3[(c >> 32) & 0xff] ~ T4[(c >> 48) & 0xff]
|
||||
b += T4[(c >> 8) & 0xff] ~ T3[(c >> 24) & 0xff] ~ T2[(c >> 40) & 0xff] ~ T1[(c >> 56) & 0xff]
|
||||
b *= mul
|
||||
return a, b, c
|
||||
}
|
||||
|
||||
pass :: #force_inline proc "contextless" (a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) {
|
||||
x, y, z = round(a, b, c, d[0], mul)
|
||||
y, z, x = round(y, z, x, d[1], mul)
|
||||
z, x, y = round(z, x, y, d[2], mul)
|
||||
x, y, z = round(x, y, z, d[3], mul)
|
||||
y, z, x = round(y, z, x, d[4], mul)
|
||||
z, x, y = round(z, x, y, d[5], mul)
|
||||
x, y, z = round(x, y, z, d[6], mul)
|
||||
y, z, x = round(y, z, x, d[7], mul)
|
||||
return
|
||||
}
|
||||
|
||||
key_schedule :: #force_inline proc "contextless" (x: []u64) {
|
||||
x[0] -= x[7] ~ 0xa5a5a5a5a5a5a5a5
|
||||
x[1] ~= x[0]
|
||||
x[2] += x[1]
|
||||
x[3] -= x[2] ~ ((~x[1]) << 19)
|
||||
x[4] ~= x[3]
|
||||
x[5] += x[4]
|
||||
x[6] -= x[5] ~ ((~x[4]) >> 23)
|
||||
x[7] ~= x[6]
|
||||
x[0] += x[7]
|
||||
x[1] -= x[0] ~ ((~x[7]) << 19)
|
||||
x[2] ~= x[1]
|
||||
x[3] += x[2]
|
||||
x[4] -= x[3] ~ ((~x[2]) >> 23)
|
||||
x[5] ~= x[4]
|
||||
x[6] += x[5]
|
||||
x[7] -= x[6] ~ 0x0123456789abcdef
|
||||
}
|
||||
|
||||
compress :: #force_inline proc "contextless" (ctx: ^Tiger_Context, data: []byte) {
|
||||
a := ctx.a
|
||||
b := ctx.b
|
||||
c := ctx.c
|
||||
x := util.cast_slice([]u64, data)
|
||||
ctx.a, ctx.b, ctx.c = pass(ctx.a, ctx.b, ctx.c, x, 5)
|
||||
key_schedule(x)
|
||||
ctx.c, ctx.a, ctx.b = pass(ctx.c, ctx.a, ctx.b, x, 7)
|
||||
key_schedule(x)
|
||||
ctx.b, ctx.c, ctx.a = pass(ctx.b, ctx.c, ctx.a, x, 9)
|
||||
ctx.a ~= a
|
||||
ctx.b -= b
|
||||
ctx.c += c
|
||||
}
|
||||
|
||||
init :: proc "contextless" (ctx: ^Tiger_Context) {
|
||||
ctx.a = 0x0123456789abcdef
|
||||
ctx.b = 0xfedcba9876543210
|
||||
ctx.c = 0xf096a5b4c3b2e187
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Tiger_Context, input: []byte) {
|
||||
p := make([]byte, len(input))
|
||||
copy(p, input)
|
||||
|
||||
length := len(p)
|
||||
ctx.length += u64(length)
|
||||
if ctx.nx > 0 {
|
||||
n := len(p)
|
||||
if n > 64 - ctx.nx {
|
||||
n = 64 - ctx.nx
|
||||
}
|
||||
copy(ctx.x[ctx.nx:ctx.nx + n], p[:n])
|
||||
ctx.nx += n
|
||||
if ctx.nx == 64 {
|
||||
compress(ctx, ctx.x[:64 - 1])
|
||||
ctx.nx = 0
|
||||
}
|
||||
p = p[n:]
|
||||
}
|
||||
for len(p) >= 64 {
|
||||
compress(ctx, p[:64])
|
||||
p = p[64:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
ctx.nx = copy(ctx.x[:], p)
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Tiger_Context, hash: []byte) {
|
||||
length := ctx.length
|
||||
tmp: [64]byte
|
||||
if ctx.ver == 1 {
|
||||
tmp[0] = 0x01
|
||||
} else {
|
||||
tmp[0] = 0x80
|
||||
}
|
||||
|
||||
size := length & 0x3f
|
||||
if size < 56 {
|
||||
update(ctx, tmp[:56 - size])
|
||||
} else {
|
||||
update(ctx, tmp[:64 + 56 - size])
|
||||
}
|
||||
|
||||
length <<= 3
|
||||
for i := uint(0); i < 8; i += 1 {
|
||||
tmp[i] = byte(length >> (8 * i))
|
||||
}
|
||||
update(ctx, tmp[:8])
|
||||
|
||||
for i := uint(0); i < 8; i += 1 {
|
||||
tmp[i] = byte(ctx.a >> (8 * i))
|
||||
tmp[i + 8] = byte(ctx.b >> (8 * i))
|
||||
tmp[i + 16] = byte(ctx.c >> (8 * i))
|
||||
}
|
||||
copy(hash[:], tmp[:len(hash)])
|
||||
}
|
||||
@@ -0,0 +1,726 @@
|
||||
package blake
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the BLAKE hashing algorithm, as defined in <https://web.archive.org/web/20190915215948/https://131002.net/blake>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_224 :: 28
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_384 :: 48
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_224 :: proc "contextless" (data: string) -> [DIGEST_SIZE_224]byte {
|
||||
return hash_bytes_224(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_224 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_224 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_224 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_224(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_224(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_224]byte{}, false
|
||||
}
|
||||
|
||||
hash_224 :: proc {
|
||||
hash_stream_224,
|
||||
hash_file_224,
|
||||
hash_bytes_224,
|
||||
hash_string_224,
|
||||
hash_bytes_to_buffer_224,
|
||||
hash_string_to_buffer_224,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc "contextless" (data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_384 :: proc "contextless" (data: string) -> [DIGEST_SIZE_384]byte {
|
||||
return hash_bytes_384(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_384 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_384 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_384 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_384(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_384(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_384]byte{}, false
|
||||
}
|
||||
|
||||
hash_384 :: proc {
|
||||
hash_stream_384,
|
||||
hash_file_384,
|
||||
hash_bytes_384,
|
||||
hash_string_384,
|
||||
hash_bytes_to_buffer_384,
|
||||
hash_string_to_buffer_384,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc "contextless" (data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc "contextless" (ctx: ^$T) {
|
||||
when T == Blake256_Context {
|
||||
if ctx.is224 {
|
||||
ctx.h[0] = 0xc1059ed8
|
||||
ctx.h[1] = 0x367cd507
|
||||
ctx.h[2] = 0x3070dd17
|
||||
ctx.h[3] = 0xf70e5939
|
||||
ctx.h[4] = 0xffc00b31
|
||||
ctx.h[5] = 0x68581511
|
||||
ctx.h[6] = 0x64f98fa7
|
||||
ctx.h[7] = 0xbefa4fa4
|
||||
} else {
|
||||
ctx.h[0] = 0x6a09e667
|
||||
ctx.h[1] = 0xbb67ae85
|
||||
ctx.h[2] = 0x3c6ef372
|
||||
ctx.h[3] = 0xa54ff53a
|
||||
ctx.h[4] = 0x510e527f
|
||||
ctx.h[5] = 0x9b05688c
|
||||
ctx.h[6] = 0x1f83d9ab
|
||||
ctx.h[7] = 0x5be0cd19
|
||||
}
|
||||
} else when T == Blake512_Context {
|
||||
if ctx.is384 {
|
||||
ctx.h[0] = 0xcbbb9d5dc1059ed8
|
||||
ctx.h[1] = 0x629a292a367cd507
|
||||
ctx.h[2] = 0x9159015a3070dd17
|
||||
ctx.h[3] = 0x152fecd8f70e5939
|
||||
ctx.h[4] = 0x67332667ffc00b31
|
||||
ctx.h[5] = 0x8eb44a8768581511
|
||||
ctx.h[6] = 0xdb0c2e0d64f98fa7
|
||||
ctx.h[7] = 0x47b5481dbefa4fa4
|
||||
} else {
|
||||
ctx.h[0] = 0x6a09e667f3bcc908
|
||||
ctx.h[1] = 0xbb67ae8584caa73b
|
||||
ctx.h[2] = 0x3c6ef372fe94f82b
|
||||
ctx.h[3] = 0xa54ff53a5f1d36f1
|
||||
ctx.h[4] = 0x510e527fade682d1
|
||||
ctx.h[5] = 0x9b05688c2b3e6c1f
|
||||
ctx.h[6] = 0x1f83d9abfb41bd6b
|
||||
ctx.h[7] = 0x5be0cd19137e2179
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^$T, data: []byte) {
|
||||
data := data
|
||||
when T == Blake256_Context {
|
||||
if ctx.nx > 0 {
|
||||
n := copy(ctx.x[ctx.nx:], data)
|
||||
ctx.nx += n
|
||||
if ctx.nx == BLOCKSIZE_256 {
|
||||
block256(ctx, ctx.x[:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= BLOCKSIZE_256 {
|
||||
n := len(data) &~ (BLOCKSIZE_256 - 1)
|
||||
block256(ctx, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) > 0 {
|
||||
ctx.nx = copy(ctx.x[:], data)
|
||||
}
|
||||
} else when T == Blake512_Context {
|
||||
if ctx.nx > 0 {
|
||||
n := copy(ctx.x[ctx.nx:], data)
|
||||
ctx.nx += n
|
||||
if ctx.nx == BLOCKSIZE_512 {
|
||||
block512(ctx, ctx.x[:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= BLOCKSIZE_512 {
|
||||
n := len(data) &~ (BLOCKSIZE_512 - 1)
|
||||
block512(ctx, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) > 0 {
|
||||
ctx.nx = copy(ctx.x[:], data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^$T, hash: []byte) {
|
||||
when T == Blake256_Context {
|
||||
tmp: [65]byte
|
||||
} else when T == Blake512_Context {
|
||||
tmp: [129]byte
|
||||
}
|
||||
nx := u64(ctx.nx)
|
||||
tmp[0] = 0x80
|
||||
length := (ctx.t + nx) << 3
|
||||
|
||||
when T == Blake256_Context {
|
||||
if nx == 55 {
|
||||
if ctx.is224 {
|
||||
write_additional(ctx, {0x80})
|
||||
} else {
|
||||
write_additional(ctx, {0x81})
|
||||
}
|
||||
} else {
|
||||
if nx < 55 {
|
||||
if nx == 0 {
|
||||
ctx.nullt = true
|
||||
}
|
||||
write_additional(ctx, tmp[0 : 55 - nx])
|
||||
} else {
|
||||
write_additional(ctx, tmp[0 : 64 - nx])
|
||||
write_additional(ctx, tmp[1:56])
|
||||
ctx.nullt = true
|
||||
}
|
||||
if ctx.is224 {
|
||||
write_additional(ctx, {0x00})
|
||||
} else {
|
||||
write_additional(ctx, {0x01})
|
||||
}
|
||||
}
|
||||
|
||||
for i : uint = 0; i < 8; i += 1 {
|
||||
tmp[i] = byte(length >> (56 - 8 * i))
|
||||
}
|
||||
write_additional(ctx, tmp[0:8])
|
||||
|
||||
h := ctx.h[:]
|
||||
if ctx.is224 {
|
||||
h = h[0:7]
|
||||
}
|
||||
for s, i in h {
|
||||
hash[i * 4] = byte(s >> 24)
|
||||
hash[i * 4 + 1] = byte(s >> 16)
|
||||
hash[i * 4 + 2] = byte(s >> 8)
|
||||
hash[i * 4 + 3] = byte(s)
|
||||
}
|
||||
} else when T == Blake512_Context {
|
||||
if nx == 111 {
|
||||
if ctx.is384 {
|
||||
write_additional(ctx, {0x80})
|
||||
} else {
|
||||
write_additional(ctx, {0x81})
|
||||
}
|
||||
} else {
|
||||
if nx < 111 {
|
||||
if nx == 0 {
|
||||
ctx.nullt = true
|
||||
}
|
||||
write_additional(ctx, tmp[0 : 111 - nx])
|
||||
} else {
|
||||
write_additional(ctx, tmp[0 : 128 - nx])
|
||||
write_additional(ctx, tmp[1:112])
|
||||
ctx.nullt = true
|
||||
}
|
||||
if ctx.is384 {
|
||||
write_additional(ctx, {0x00})
|
||||
} else {
|
||||
write_additional(ctx, {0x01})
|
||||
}
|
||||
}
|
||||
|
||||
for i : uint = 0; i < 16; i += 1 {
|
||||
tmp[i] = byte(length >> (120 - 8 * i))
|
||||
}
|
||||
write_additional(ctx, tmp[0:16])
|
||||
|
||||
h := ctx.h[:]
|
||||
if ctx.is384 {
|
||||
h = h[0:6]
|
||||
}
|
||||
for s, i in h {
|
||||
hash[i * 8] = byte(s >> 56)
|
||||
hash[i * 8 + 1] = byte(s >> 48)
|
||||
hash[i * 8 + 2] = byte(s >> 40)
|
||||
hash[i * 8 + 3] = byte(s >> 32)
|
||||
hash[i * 8 + 4] = byte(s >> 24)
|
||||
hash[i * 8 + 5] = byte(s >> 16)
|
||||
hash[i * 8 + 6] = byte(s >> 8)
|
||||
hash[i * 8 + 7] = byte(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SIZE_224 :: 28
|
||||
SIZE_256 :: 32
|
||||
SIZE_384 :: 48
|
||||
SIZE_512 :: 64
|
||||
BLOCKSIZE_256 :: 64
|
||||
BLOCKSIZE_512 :: 128
|
||||
|
||||
Blake256_Context :: struct {
|
||||
h: [8]u32,
|
||||
s: [4]u32,
|
||||
t: u64,
|
||||
x: [64]byte,
|
||||
nx: int,
|
||||
is224: bool,
|
||||
nullt: bool,
|
||||
}
|
||||
|
||||
Blake512_Context :: struct {
|
||||
h: [8]u64,
|
||||
s: [4]u64,
|
||||
t: u64,
|
||||
x: [128]byte,
|
||||
nx: int,
|
||||
is384: bool,
|
||||
nullt: bool,
|
||||
}
|
||||
|
||||
SIGMA := [?]int {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
|
||||
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
|
||||
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
|
||||
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
|
||||
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
|
||||
12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
|
||||
13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
|
||||
6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
|
||||
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
|
||||
}
|
||||
|
||||
U256 := [16]u32 {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
}
|
||||
|
||||
U512 := [16]u64 {
|
||||
0x243f6a8885a308d3, 0x13198a2e03707344, 0xa4093822299f31d0, 0x082efa98ec4e6c89,
|
||||
0x452821e638d01377, 0xbe5466cf34e90c6c, 0xc0ac29b7c97c50dd, 0x3f84d5b5b5470917,
|
||||
0x9216d5d98979fb1b, 0xd1310ba698dfb5ac, 0x2ffd72dbd01adfb7, 0xb8e1afed6a267e96,
|
||||
0xba7c9045f12c7f99, 0x24a19947b3916cf7, 0x0801f2e2858efc16, 0x636920d871574e69,
|
||||
}
|
||||
|
||||
G256 :: #force_inline proc "contextless" (a, b, c, d: u32, m: [16]u32, i, j: int) -> (u32, u32, u32, u32) {
|
||||
a, b, c, d := a, b, c, d
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (32 - 16) | d >> 16
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (32 - 12) | b >> 12
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (32 - 8) | d >> 8
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (32 - 7) | b >> 7
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int) -> (u64, u64, u64, u64) {
|
||||
a, b, c, d := a, b, c, d
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (64 - 32) | d >> 32
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (64 - 25) | b >> 25
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (64 - 16) | d >> 16
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (64 - 11) | b >> 11
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) #no_bounds_check {
|
||||
i, j: int = ---, ---
|
||||
v, m: [16]u32 = ---, ---
|
||||
p := p
|
||||
for len(p) >= BLOCKSIZE_256 {
|
||||
v[0] = ctx.h[0]
|
||||
v[1] = ctx.h[1]
|
||||
v[2] = ctx.h[2]
|
||||
v[3] = ctx.h[3]
|
||||
v[4] = ctx.h[4]
|
||||
v[5] = ctx.h[5]
|
||||
v[6] = ctx.h[6]
|
||||
v[7] = ctx.h[7]
|
||||
v[8] = ctx.s[0] ~ U256[0]
|
||||
v[9] = ctx.s[1] ~ U256[1]
|
||||
v[10] = ctx.s[2] ~ U256[2]
|
||||
v[11] = ctx.s[3] ~ U256[3]
|
||||
v[12] = U256[4]
|
||||
v[13] = U256[5]
|
||||
v[14] = U256[6]
|
||||
v[15] = U256[7]
|
||||
|
||||
ctx.t += 512
|
||||
if !ctx.nullt {
|
||||
v[12] ~= u32(ctx.t)
|
||||
v[13] ~= u32(ctx.t)
|
||||
v[14] ~= u32(ctx.t >> 32)
|
||||
v[15] ~= u32(ctx.t >> 32)
|
||||
}
|
||||
|
||||
for i, j = 0, 0; i < 16; i, j = i+1, j+4 {
|
||||
m[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3])
|
||||
}
|
||||
|
||||
for i = 0; i < 14; i += 1 {
|
||||
v[0], v[4], v[8], v[12] = G256(v[0], v[4], v[8], v[12], m, i, 0)
|
||||
v[1], v[5], v[9], v[13] = G256(v[1], v[5], v[9], v[13], m, i, 1)
|
||||
v[2], v[6], v[10], v[14] = G256(v[2], v[6], v[10], v[14], m, i, 2)
|
||||
v[3], v[7], v[11], v[15] = G256(v[3], v[7], v[11], v[15], m, i, 3)
|
||||
v[0], v[5], v[10], v[15] = G256(v[0], v[5], v[10], v[15], m, i, 4)
|
||||
v[1], v[6], v[11], v[12] = G256(v[1], v[6], v[11], v[12], m, i, 5)
|
||||
v[2], v[7], v[8], v[13] = G256(v[2], v[7], v[8], v[13], m, i, 6)
|
||||
v[3], v[4], v[9], v[14] = G256(v[3], v[4], v[9], v[14], m, i, 7)
|
||||
}
|
||||
|
||||
for i = 0; i < 8; i += 1 {
|
||||
ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
|
||||
}
|
||||
p = p[BLOCKSIZE_256:]
|
||||
}
|
||||
}
|
||||
|
||||
block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check {
|
||||
i, j: int = ---, ---
|
||||
v, m: [16]u64 = ---, ---
|
||||
p := p
|
||||
for len(p) >= BLOCKSIZE_512 {
|
||||
v[0] = ctx.h[0]
|
||||
v[1] = ctx.h[1]
|
||||
v[2] = ctx.h[2]
|
||||
v[3] = ctx.h[3]
|
||||
v[4] = ctx.h[4]
|
||||
v[5] = ctx.h[5]
|
||||
v[6] = ctx.h[6]
|
||||
v[7] = ctx.h[7]
|
||||
v[8] = ctx.s[0] ~ U512[0]
|
||||
v[9] = ctx.s[1] ~ U512[1]
|
||||
v[10] = ctx.s[2] ~ U512[2]
|
||||
v[11] = ctx.s[3] ~ U512[3]
|
||||
v[12] = U512[4]
|
||||
v[13] = U512[5]
|
||||
v[14] = U512[6]
|
||||
v[15] = U512[7]
|
||||
|
||||
ctx.t += 1024
|
||||
if !ctx.nullt {
|
||||
v[12] ~= ctx.t
|
||||
v[13] ~= ctx.t
|
||||
v[14] ~= 0
|
||||
v[15] ~= 0
|
||||
}
|
||||
|
||||
for i, j = 0, 0; i < 16; i, j = i + 1, j + 8 {
|
||||
m[i] = u64(p[j]) << 56 | u64(p[j + 1]) << 48 | u64(p[j + 2]) << 40 | u64(p[j + 3]) << 32 |
|
||||
u64(p[j + 4]) << 24 | u64(p[j + 5]) << 16 | u64(p[j + 6]) << 8 | u64(p[j + 7])
|
||||
}
|
||||
for i = 0; i < 16; i += 1 {
|
||||
v[0], v[4], v[8], v[12] = G512(v[0], v[4], v[8], v[12], m, i, 0)
|
||||
v[1], v[5], v[9], v[13] = G512(v[1], v[5], v[9], v[13], m, i, 1)
|
||||
v[2], v[6], v[10], v[14] = G512(v[2], v[6], v[10], v[14], m, i, 2)
|
||||
v[3], v[7], v[11], v[15] = G512(v[3], v[7], v[11], v[15], m, i, 3)
|
||||
v[0], v[5], v[10], v[15] = G512(v[0], v[5], v[10], v[15], m, i, 4)
|
||||
v[1], v[6], v[11], v[12] = G512(v[1], v[6], v[11], v[12], m, i, 5)
|
||||
v[2], v[7], v[8], v[13] = G512(v[2], v[7], v[8], v[13], m, i, 6)
|
||||
v[3], v[4], v[9], v[14] = G512(v[3], v[4], v[9], v[14], m, i, 7)
|
||||
}
|
||||
|
||||
for i = 0; i < 8; i += 1 {
|
||||
ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
|
||||
}
|
||||
p = p[BLOCKSIZE_512:]
|
||||
}
|
||||
}
|
||||
|
||||
write_additional :: proc "contextless" (ctx: ^$T, data: []byte) {
|
||||
ctx.t -= u64(len(data)) << 3
|
||||
update(ctx, data)
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package blake2b
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the BLAKE2B hashing algorithm.
|
||||
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../_blake2"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 64
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2b_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _blake2.Blake2b_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash)
|
||||
}
|
||||
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2b_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_blake2.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Blake2b_Context :: _blake2.Blake2b_Context
|
||||
|
||||
init :: proc(ctx: ^_blake2.Blake2b_Context) {
|
||||
_blake2.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package blake2s
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the BLAKE2S hashing algorithm.
|
||||
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../_blake2"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 32
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2s_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _blake2.Blake2s_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2s_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_blake2.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Blake2s_Context :: _blake2.Blake2b_Context
|
||||
|
||||
init :: proc(ctx: ^_blake2.Blake2s_Context) {
|
||||
_blake2.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
}
|
||||
@@ -0,0 +1,581 @@
|
||||
package chacha20
|
||||
|
||||
import "core:crypto/util"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
|
||||
KEY_SIZE :: 32
|
||||
NONCE_SIZE :: 12
|
||||
XNONCE_SIZE :: 24
|
||||
|
||||
_MAX_CTR_IETF :: 0xffffffff
|
||||
|
||||
_BLOCK_SIZE :: 64
|
||||
_STATE_SIZE_U32 :: 16
|
||||
_ROUNDS :: 20
|
||||
|
||||
_SIGMA_0 : u32 : 0x61707865
|
||||
_SIGMA_1 : u32 : 0x3320646e
|
||||
_SIGMA_2 : u32 : 0x79622d32
|
||||
_SIGMA_3 : u32 : 0x6b206574
|
||||
|
||||
Context :: struct {
|
||||
_s: [_STATE_SIZE_U32]u32,
|
||||
|
||||
_buffer: [_BLOCK_SIZE]byte,
|
||||
_off: int,
|
||||
|
||||
_is_ietf_flavor: bool,
|
||||
_is_initialized: bool,
|
||||
}
|
||||
|
||||
init :: proc (ctx: ^Context, key, nonce: []byte) {
|
||||
if len(key) != KEY_SIZE {
|
||||
panic("crypto/chacha20: invalid ChaCha20 key size")
|
||||
}
|
||||
if n_len := len(nonce); n_len != NONCE_SIZE && n_len != XNONCE_SIZE {
|
||||
panic("crypto/chacha20: invalid (X)ChaCha20 nonce size")
|
||||
}
|
||||
|
||||
k, n := key, nonce
|
||||
|
||||
// Derive the XChaCha20 subkey and sub-nonce via HChaCha20.
|
||||
is_xchacha := len(nonce) == XNONCE_SIZE
|
||||
if is_xchacha {
|
||||
sub_key := ctx._buffer[:KEY_SIZE]
|
||||
_hchacha20(sub_key, k, n)
|
||||
k = sub_key
|
||||
n = n[16:24]
|
||||
}
|
||||
|
||||
ctx._s[0] = _SIGMA_0
|
||||
ctx._s[1] = _SIGMA_1
|
||||
ctx._s[2] = _SIGMA_2
|
||||
ctx._s[3] = _SIGMA_3
|
||||
ctx._s[4] = util.U32_LE(k[0:4])
|
||||
ctx._s[5] = util.U32_LE(k[4:8])
|
||||
ctx._s[6] = util.U32_LE(k[8:12])
|
||||
ctx._s[7] = util.U32_LE(k[12:16])
|
||||
ctx._s[8] = util.U32_LE(k[16:20])
|
||||
ctx._s[9] = util.U32_LE(k[20:24])
|
||||
ctx._s[10] = util.U32_LE(k[24:28])
|
||||
ctx._s[11] = util.U32_LE(k[28:32])
|
||||
ctx._s[12] = 0
|
||||
if !is_xchacha {
|
||||
ctx._s[13] = util.U32_LE(n[0:4])
|
||||
ctx._s[14] = util.U32_LE(n[4:8])
|
||||
ctx._s[15] = util.U32_LE(n[8:12])
|
||||
} else {
|
||||
ctx._s[13] = 0
|
||||
ctx._s[14] = util.U32_LE(n[0:4])
|
||||
ctx._s[15] = util.U32_LE(n[4:8])
|
||||
|
||||
// The sub-key is stored in the keystream buffer. While
|
||||
// this will be overwritten in most circumstances, explicitly
|
||||
// clear it out early.
|
||||
mem.zero_explicit(&ctx._buffer, KEY_SIZE)
|
||||
}
|
||||
|
||||
ctx._off = _BLOCK_SIZE
|
||||
ctx._is_ietf_flavor = !is_xchacha
|
||||
ctx._is_initialized = true
|
||||
}
|
||||
|
||||
seek :: proc (ctx: ^Context, block_nr: u64) {
|
||||
assert(ctx._is_initialized)
|
||||
|
||||
if ctx._is_ietf_flavor {
|
||||
if block_nr > _MAX_CTR_IETF {
|
||||
panic("crypto/chacha20: attempted to seek past maximum counter")
|
||||
}
|
||||
} else {
|
||||
ctx._s[13] = u32(block_nr >> 32)
|
||||
}
|
||||
ctx._s[12] = u32(block_nr)
|
||||
ctx._off = _BLOCK_SIZE
|
||||
}
|
||||
|
||||
xor_bytes :: proc (ctx: ^Context, dst, src: []byte) {
|
||||
assert(ctx._is_initialized)
|
||||
|
||||
// TODO: Enforcing that dst and src alias exactly or not at all
|
||||
// is a good idea, though odd aliasing should be extremely uncommon.
|
||||
|
||||
src, dst := src, dst
|
||||
if dst_len := len(dst); dst_len < len(src) {
|
||||
src = src[:dst_len]
|
||||
}
|
||||
|
||||
for remaining := len(src); remaining > 0; {
|
||||
// Process multiple blocks at once
|
||||
if ctx._off == _BLOCK_SIZE {
|
||||
if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 {
|
||||
direct_bytes := nr_blocks * _BLOCK_SIZE
|
||||
_do_blocks(ctx, dst, src, nr_blocks)
|
||||
remaining -= direct_bytes
|
||||
if remaining == 0 {
|
||||
return
|
||||
}
|
||||
dst = dst[direct_bytes:]
|
||||
src = src[direct_bytes:]
|
||||
}
|
||||
|
||||
// If there is a partial block, generate and buffer 1 block
|
||||
// worth of keystream.
|
||||
_do_blocks(ctx, ctx._buffer[:], nil, 1)
|
||||
ctx._off = 0
|
||||
}
|
||||
|
||||
// Process partial blocks from the buffered keystream.
|
||||
to_xor := min(_BLOCK_SIZE - ctx._off, remaining)
|
||||
buffered_keystream := ctx._buffer[ctx._off:]
|
||||
for i := 0; i < to_xor; i = i + 1 {
|
||||
dst[i] = buffered_keystream[i] ~ src[i]
|
||||
}
|
||||
ctx._off += to_xor
|
||||
dst = dst[to_xor:]
|
||||
src = src[to_xor:]
|
||||
remaining -= to_xor
|
||||
}
|
||||
}
|
||||
|
||||
keystream_bytes :: proc (ctx: ^Context, dst: []byte) {
|
||||
assert(ctx._is_initialized)
|
||||
|
||||
dst := dst
|
||||
for remaining := len(dst); remaining > 0; {
|
||||
// Process multiple blocks at once
|
||||
if ctx._off == _BLOCK_SIZE {
|
||||
if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 {
|
||||
direct_bytes := nr_blocks * _BLOCK_SIZE
|
||||
_do_blocks(ctx, dst, nil, nr_blocks)
|
||||
remaining -= direct_bytes
|
||||
if remaining == 0 {
|
||||
return
|
||||
}
|
||||
dst = dst[direct_bytes:]
|
||||
}
|
||||
|
||||
// If there is a partial block, generate and buffer 1 block
|
||||
// worth of keystream.
|
||||
_do_blocks(ctx, ctx._buffer[:], nil, 1)
|
||||
ctx._off = 0
|
||||
}
|
||||
|
||||
// Process partial blocks from the buffered keystream.
|
||||
to_copy := min(_BLOCK_SIZE - ctx._off, remaining)
|
||||
buffered_keystream := ctx._buffer[ctx._off:]
|
||||
copy(dst[:to_copy], buffered_keystream[:to_copy])
|
||||
ctx._off += to_copy
|
||||
dst = dst[to_copy:]
|
||||
remaining -= to_copy
|
||||
}
|
||||
}
|
||||
|
||||
reset :: proc (ctx: ^Context) {
|
||||
mem.zero_explicit(&ctx._s, size_of(ctx._s))
|
||||
mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer))
|
||||
|
||||
ctx._is_initialized = false
|
||||
}
|
||||
|
||||
_do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per nonce.
|
||||
//
|
||||
// While all modern "standard" definitions of ChaCha20 use
|
||||
// the IETF 32-bit counter, for XChaCha20 most common
|
||||
// implementations allow for a 64-bit counter.
|
||||
//
|
||||
// Honestly, the answer here is "use a MRAE primitive", but
|
||||
// go with common practice in the case of XChaCha20.
|
||||
if ctx._is_ietf_flavor {
|
||||
if u64(ctx._s[12]) + u64(nr_blocks) > 0xffffffff {
|
||||
panic("crypto/chacha20: maximum ChaCha20 keystream per nonce reached")
|
||||
}
|
||||
} else {
|
||||
ctr := (u64(ctx._s[13]) << 32) | u64(ctx._s[12])
|
||||
if _, carry := bits.add_u64(ctr, u64(nr_blocks), 0); carry != 0 {
|
||||
panic("crypto/chacha20: maximum XChaCha20 keystream per nonce reached")
|
||||
}
|
||||
}
|
||||
|
||||
dst, src := dst, src
|
||||
x := &ctx._s
|
||||
for n := 0; n < nr_blocks; n = n + 1 {
|
||||
x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3
|
||||
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
|
||||
|
||||
for i := _ROUNDS; i > 0; i = i - 2 {
|
||||
// Even when forcing inlining manually inlining all of
|
||||
// these is decently faster.
|
||||
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
}
|
||||
|
||||
x0 += _SIGMA_0
|
||||
x1 += _SIGMA_1
|
||||
x2 += _SIGMA_2
|
||||
x3 += _SIGMA_3
|
||||
x4 += x[4]
|
||||
x5 += x[5]
|
||||
x6 += x[6]
|
||||
x7 += x[7]
|
||||
x8 += x[8]
|
||||
x9 += x[9]
|
||||
x10 += x[10]
|
||||
x11 += x[11]
|
||||
x12 += x[12]
|
||||
x13 += x[13]
|
||||
x14 += x[14]
|
||||
x15 += x[15]
|
||||
|
||||
// While the "correct" answer to getting more performance out of
|
||||
// this is "use vector operations", support for that is currently
|
||||
// a work in progress/to be designed.
|
||||
//
|
||||
// Until dedicated assembly can be written leverage the fact that
|
||||
// the callers of this routine ensure that src/dst are valid.
|
||||
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
||||
// systems that also happen to not be strict about aligned
|
||||
// memory access.
|
||||
|
||||
dst_p := transmute(^[16]u32)(&dst[0])
|
||||
if src != nil {
|
||||
src_p := transmute(^[16]u32)(&src[0])
|
||||
dst_p[0] = src_p[0] ~ x0
|
||||
dst_p[1] = src_p[1] ~ x1
|
||||
dst_p[2] = src_p[2] ~ x2
|
||||
dst_p[3] = src_p[3] ~ x3
|
||||
dst_p[4] = src_p[4] ~ x4
|
||||
dst_p[5] = src_p[5] ~ x5
|
||||
dst_p[6] = src_p[6] ~ x6
|
||||
dst_p[7] = src_p[7] ~ x7
|
||||
dst_p[8] = src_p[8] ~ x8
|
||||
dst_p[9] = src_p[9] ~ x9
|
||||
dst_p[10] = src_p[10] ~ x10
|
||||
dst_p[11] = src_p[11] ~ x11
|
||||
dst_p[12] = src_p[12] ~ x12
|
||||
dst_p[13] = src_p[13] ~ x13
|
||||
dst_p[14] = src_p[14] ~ x14
|
||||
dst_p[15] = src_p[15] ~ x15
|
||||
src = src[_BLOCK_SIZE:]
|
||||
} else {
|
||||
dst_p[0] = x0
|
||||
dst_p[1] = x1
|
||||
dst_p[2] = x2
|
||||
dst_p[3] = x3
|
||||
dst_p[4] = x4
|
||||
dst_p[5] = x5
|
||||
dst_p[6] = x6
|
||||
dst_p[7] = x7
|
||||
dst_p[8] = x8
|
||||
dst_p[9] = x9
|
||||
dst_p[10] = x10
|
||||
dst_p[11] = x11
|
||||
dst_p[12] = x12
|
||||
dst_p[13] = x13
|
||||
dst_p[14] = x14
|
||||
dst_p[15] = x15
|
||||
}
|
||||
dst = dst[_BLOCK_SIZE:]
|
||||
} else {
|
||||
#no_bounds_check {
|
||||
if src != nil {
|
||||
util.PUT_U32_LE(dst[0:4], util.U32_LE(src[0:4]) ~ x0)
|
||||
util.PUT_U32_LE(dst[4:8], util.U32_LE(src[4:8]) ~ x1)
|
||||
util.PUT_U32_LE(dst[8:12], util.U32_LE(src[8:12]) ~ x2)
|
||||
util.PUT_U32_LE(dst[12:16], util.U32_LE(src[12:16]) ~ x3)
|
||||
util.PUT_U32_LE(dst[16:20], util.U32_LE(src[16:20]) ~ x4)
|
||||
util.PUT_U32_LE(dst[20:24], util.U32_LE(src[20:24]) ~ x5)
|
||||
util.PUT_U32_LE(dst[24:28], util.U32_LE(src[24:28]) ~ x6)
|
||||
util.PUT_U32_LE(dst[28:32], util.U32_LE(src[28:32]) ~ x7)
|
||||
util.PUT_U32_LE(dst[32:36], util.U32_LE(src[32:36]) ~ x8)
|
||||
util.PUT_U32_LE(dst[36:40], util.U32_LE(src[36:40]) ~ x9)
|
||||
util.PUT_U32_LE(dst[40:44], util.U32_LE(src[40:44]) ~ x10)
|
||||
util.PUT_U32_LE(dst[44:48], util.U32_LE(src[44:48]) ~ x11)
|
||||
util.PUT_U32_LE(dst[48:52], util.U32_LE(src[48:52]) ~ x12)
|
||||
util.PUT_U32_LE(dst[52:56], util.U32_LE(src[52:56]) ~ x13)
|
||||
util.PUT_U32_LE(dst[56:60], util.U32_LE(src[56:60]) ~ x14)
|
||||
util.PUT_U32_LE(dst[60:64], util.U32_LE(src[60:64]) ~ x15)
|
||||
src = src[_BLOCK_SIZE:]
|
||||
} else {
|
||||
util.PUT_U32_LE(dst[0:4], x0)
|
||||
util.PUT_U32_LE(dst[4:8], x1)
|
||||
util.PUT_U32_LE(dst[8:12], x2)
|
||||
util.PUT_U32_LE(dst[12:16], x3)
|
||||
util.PUT_U32_LE(dst[16:20], x4)
|
||||
util.PUT_U32_LE(dst[20:24], x5)
|
||||
util.PUT_U32_LE(dst[24:28], x6)
|
||||
util.PUT_U32_LE(dst[28:32], x7)
|
||||
util.PUT_U32_LE(dst[32:36], x8)
|
||||
util.PUT_U32_LE(dst[36:40], x9)
|
||||
util.PUT_U32_LE(dst[40:44], x10)
|
||||
util.PUT_U32_LE(dst[44:48], x11)
|
||||
util.PUT_U32_LE(dst[48:52], x12)
|
||||
util.PUT_U32_LE(dst[52:56], x13)
|
||||
util.PUT_U32_LE(dst[56:60], x14)
|
||||
util.PUT_U32_LE(dst[60:64], x15)
|
||||
}
|
||||
dst = dst[_BLOCK_SIZE:]
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the counter. Overflow checking is done upon
|
||||
// entry into the routine, so a 64-bit increment safely
|
||||
// covers both cases.
|
||||
new_ctr := ((u64(ctx._s[13]) << 32) | u64(ctx._s[12])) + 1
|
||||
x[12] = u32(new_ctr)
|
||||
x[13] = u32(new_ctr >> 32)
|
||||
}
|
||||
}
|
||||
|
||||
_hchacha20 :: proc (dst, key, nonce: []byte) {
|
||||
x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3
|
||||
x4 := util.U32_LE(key[0:4])
|
||||
x5 := util.U32_LE(key[4:8])
|
||||
x6 := util.U32_LE(key[8:12])
|
||||
x7 := util.U32_LE(key[12:16])
|
||||
x8 := util.U32_LE(key[16:20])
|
||||
x9 := util.U32_LE(key[20:24])
|
||||
x10 := util.U32_LE(key[24:28])
|
||||
x11 := util.U32_LE(key[28:32])
|
||||
x12 := util.U32_LE(nonce[0:4])
|
||||
x13 := util.U32_LE(nonce[4:8])
|
||||
x14 := util.U32_LE(nonce[8:12])
|
||||
x15 := util.U32_LE(nonce[12:16])
|
||||
|
||||
for i := _ROUNDS; i > 0; i = i - 2 {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
}
|
||||
|
||||
util.PUT_U32_LE(dst[0:4], x0)
|
||||
util.PUT_U32_LE(dst[4:8], x1)
|
||||
util.PUT_U32_LE(dst[8:12], x2)
|
||||
util.PUT_U32_LE(dst[12:16], x3)
|
||||
util.PUT_U32_LE(dst[16:20], x12)
|
||||
util.PUT_U32_LE(dst[20:24], x13)
|
||||
util.PUT_U32_LE(dst[24:28], x14)
|
||||
util.PUT_U32_LE(dst[28:32], x15)
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package chacha20poly1305
|
||||
|
||||
import "core:crypto"
|
||||
import "core:crypto/chacha20"
|
||||
import "core:crypto/poly1305"
|
||||
import "core:crypto/util"
|
||||
import "core:mem"
|
||||
|
||||
KEY_SIZE :: chacha20.KEY_SIZE
|
||||
NONCE_SIZE :: chacha20.NONCE_SIZE
|
||||
TAG_SIZE :: poly1305.TAG_SIZE
|
||||
|
||||
_P_MAX :: 64 * 0xffffffff // 64 * (2^32-1)
|
||||
|
||||
_validate_common_slice_sizes :: proc (tag, key, nonce, aad, text: []byte) {
|
||||
if len(tag) != TAG_SIZE {
|
||||
panic("crypto/chacha20poly1305: invalid destination tag size")
|
||||
}
|
||||
if len(key) != KEY_SIZE {
|
||||
panic("crypto/chacha20poly1305: invalid key size")
|
||||
}
|
||||
if len(nonce) != NONCE_SIZE {
|
||||
panic("crypto/chacha20poly1305: invalid nonce size")
|
||||
}
|
||||
|
||||
#assert(size_of(int) == 8 || size_of(int) <= 4)
|
||||
when size_of(int) == 8 {
|
||||
// A_MAX = 2^64 - 1 due to the length field limit.
|
||||
// P_MAX = 64 * (2^32 - 1) due to the IETF ChaCha20 counter limit.
|
||||
//
|
||||
// A_MAX is limited by size_of(int), so there is no need to
|
||||
// enforce it. P_MAX only needs to be checked on 64-bit targets,
|
||||
// for reasons that should be obvious.
|
||||
if text_len := len(text); text_len > _P_MAX {
|
||||
panic("crypto/chacha20poly1305: oversized src data")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_PAD: [16]byte
|
||||
_update_mac_pad16 :: #force_inline proc (ctx: ^poly1305.Context, x_len: int) {
|
||||
if pad_len := 16 - (x_len & (16-1)); pad_len != 16 {
|
||||
poly1305.update(ctx, _PAD[:pad_len])
|
||||
}
|
||||
}
|
||||
|
||||
encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
|
||||
_validate_common_slice_sizes(tag, key, nonce, aad, plaintext)
|
||||
if len(ciphertext) != len(plaintext) {
|
||||
panic("crypto/chacha20poly1305: invalid destination ciphertext size")
|
||||
}
|
||||
|
||||
stream_ctx: chacha20.Context = ---
|
||||
chacha20.init(&stream_ctx, key, nonce)
|
||||
|
||||
// otk = poly1305_key_gen(key, nonce)
|
||||
otk: [poly1305.KEY_SIZE]byte = ---
|
||||
chacha20.keystream_bytes(&stream_ctx, otk[:])
|
||||
mac_ctx: poly1305.Context = ---
|
||||
poly1305.init(&mac_ctx, otk[:])
|
||||
mem.zero_explicit(&otk, size_of(otk))
|
||||
|
||||
aad_len, ciphertext_len := len(aad), len(ciphertext)
|
||||
|
||||
// There is nothing preventing aad and ciphertext from overlapping
|
||||
// so auth the AAD before encrypting (slightly different from the
|
||||
// RFC, since the RFC encrypts into a new buffer).
|
||||
//
|
||||
// mac_data = aad | pad16(aad)
|
||||
poly1305.update(&mac_ctx, aad)
|
||||
_update_mac_pad16(&mac_ctx, aad_len)
|
||||
|
||||
// ciphertext = chacha20_encrypt(key, 1, nonce, plaintext)
|
||||
chacha20.seek(&stream_ctx, 1)
|
||||
chacha20.xor_bytes(&stream_ctx, ciphertext, plaintext)
|
||||
chacha20.reset(&stream_ctx) // Don't need the stream context anymore.
|
||||
|
||||
// mac_data |= ciphertext | pad16(ciphertext)
|
||||
poly1305.update(&mac_ctx, ciphertext)
|
||||
_update_mac_pad16(&mac_ctx, ciphertext_len)
|
||||
|
||||
// mac_data |= num_to_8_le_bytes(aad.length)
|
||||
// mac_data |= num_to_8_le_bytes(ciphertext.length)
|
||||
l_buf := otk[0:16] // Reuse the scratch buffer.
|
||||
util.PUT_U64_LE(l_buf[0:8], u64(aad_len))
|
||||
util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len))
|
||||
poly1305.update(&mac_ctx, l_buf)
|
||||
|
||||
// tag = poly1305_mac(mac_data, otk)
|
||||
poly1305.final(&mac_ctx, tag) // Implicitly sanitizes context.
|
||||
}
|
||||
|
||||
decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool {
|
||||
_validate_common_slice_sizes(tag, key, nonce, aad, ciphertext)
|
||||
if len(ciphertext) != len(plaintext) {
|
||||
panic("crypto/chacha20poly1305: invalid destination plaintext size")
|
||||
}
|
||||
|
||||
// Note: Unlike encrypt, this can fail early, so use defer for
|
||||
// sanitization rather than assuming control flow reaches certain
|
||||
// points where needed.
|
||||
|
||||
stream_ctx: chacha20.Context = ---
|
||||
chacha20.init(&stream_ctx, key, nonce)
|
||||
|
||||
// otk = poly1305_key_gen(key, nonce)
|
||||
otk: [poly1305.KEY_SIZE]byte = ---
|
||||
chacha20.keystream_bytes(&stream_ctx, otk[:])
|
||||
defer chacha20.reset(&stream_ctx)
|
||||
|
||||
mac_ctx: poly1305.Context = ---
|
||||
poly1305.init(&mac_ctx, otk[:])
|
||||
defer mem.zero_explicit(&otk, size_of(otk))
|
||||
|
||||
aad_len, ciphertext_len := len(aad), len(ciphertext)
|
||||
|
||||
// mac_data = aad | pad16(aad)
|
||||
// mac_data |= ciphertext | pad16(ciphertext)
|
||||
// mac_data |= num_to_8_le_bytes(aad.length)
|
||||
// mac_data |= num_to_8_le_bytes(ciphertext.length)
|
||||
poly1305.update(&mac_ctx, aad)
|
||||
_update_mac_pad16(&mac_ctx, aad_len)
|
||||
poly1305.update(&mac_ctx, ciphertext)
|
||||
_update_mac_pad16(&mac_ctx, ciphertext_len)
|
||||
l_buf := otk[0:16] // Reuse the scratch buffer.
|
||||
util.PUT_U64_LE(l_buf[0:8], u64(aad_len))
|
||||
util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len))
|
||||
poly1305.update(&mac_ctx, l_buf)
|
||||
|
||||
// tag = poly1305_mac(mac_data, otk)
|
||||
derived_tag := otk[0:poly1305.TAG_SIZE] // Reuse the scratch buffer again.
|
||||
poly1305.final(&mac_ctx, derived_tag) // Implicitly sanitizes context.
|
||||
|
||||
// Validate the tag in constant time.
|
||||
if crypto.compare_constant_time(tag, derived_tag) != 1 {
|
||||
// Zero out the plaintext, as a defense in depth measure.
|
||||
mem.zero_explicit(raw_data(plaintext), ciphertext_len)
|
||||
return false
|
||||
}
|
||||
|
||||
// plaintext = chacha20_decrypt(key, 1, nonce, ciphertext)
|
||||
chacha20.seek(&stream_ctx, 1)
|
||||
chacha20.xor_bytes(&stream_ctx, plaintext, ciphertext)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package crypto
|
||||
|
||||
import "core:mem"
|
||||
|
||||
// compare_constant_time returns 1 iff a and b are equal, 0 otherwise.
|
||||
//
|
||||
// The execution time of this routine is constant regardless of the contents
|
||||
// of the slices being compared, as long as the length of the slices is equal.
|
||||
// If the length of the two slices is different, it will early-return 0.
|
||||
compare_constant_time :: proc "contextless" (a, b: []byte) -> int {
|
||||
// If the length of the slices is different, early return.
|
||||
//
|
||||
// This leaks the fact that the slices have a different length,
|
||||
// but the routine is primarily intended for comparing things
|
||||
// like MACS and password digests.
|
||||
n := len(a)
|
||||
if n != len(b) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return compare_byte_ptrs_constant_time(raw_data(a), raw_data(b), n)
|
||||
}
|
||||
|
||||
// compare_byte_ptrs_constant_time returns 1 iff the bytes pointed to by
|
||||
// a and b are equal, 0 otherwise.
|
||||
//
|
||||
// The execution time of this routine is constant regardless of the
|
||||
// contents of the memory being compared.
|
||||
compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> int {
|
||||
x := mem.slice_ptr(a, n)
|
||||
y := mem.slice_ptr(b, n)
|
||||
|
||||
v: byte
|
||||
for i in 0..<n {
|
||||
v |= x[i] ~ y[i]
|
||||
}
|
||||
|
||||
// After the loop, v == 0 iff a == b. The subtraction will underflow
|
||||
// iff v == 0, setting the sign-bit, which gets returned.
|
||||
return int((u32(v)-1) >> 31)
|
||||
}
|
||||
|
||||
// rand_bytes fills the dst buffer with cryptographic entropy taken from
|
||||
// the system entropy source. This routine will block if the system entropy
|
||||
// source is not ready yet. All system entropy source failures are treated
|
||||
// as catastrophic, resulting in a panic.
|
||||
rand_bytes :: proc (dst: []byte) {
|
||||
// zero-fill the buffer first
|
||||
mem.zero_explicit(raw_data(dst), len(dst))
|
||||
|
||||
_rand_bytes(dst)
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
package gost
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the GOST hashing algorithm, as defined in RFC 5831 <https://datatracker.ietf.org/doc/html/rfc5831>
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 32
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Gost_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Gost_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Gost_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc "contextless" (ctx: ^Gost_Context) {
|
||||
sbox: [8][16]u32 = {
|
||||
{ 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15 },
|
||||
{ 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8 },
|
||||
{ 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13 },
|
||||
{ 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3 },
|
||||
{ 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5 },
|
||||
{ 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3 },
|
||||
{ 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11 },
|
||||
{ 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12 },
|
||||
}
|
||||
|
||||
i := 0
|
||||
for a := 0; a < 16; a += 1 {
|
||||
ax := sbox[1][a] << 15
|
||||
bx := sbox[3][a] << 23
|
||||
cx := sbox[5][a]
|
||||
cx = (cx >> 1) | (cx << 31)
|
||||
dx := sbox[7][a] << 7
|
||||
for b := 0; b < 16; b, i = b + 1, i + 1 {
|
||||
SBOX_1[i] = ax | (sbox[0][b] << 11)
|
||||
SBOX_2[i] = bx | (sbox[2][b] << 19)
|
||||
SBOX_3[i] = cx | (sbox[4][b] << 27)
|
||||
SBOX_4[i] = dx | (sbox[6][b] << 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Gost_Context, data: []byte) {
|
||||
length := byte(len(data))
|
||||
j: byte
|
||||
|
||||
i := ctx.partial_bytes
|
||||
for i < 32 && j < length {
|
||||
ctx.partial[i] = data[j]
|
||||
i, j = i + 1, j + 1
|
||||
}
|
||||
|
||||
if i < 32 {
|
||||
ctx.partial_bytes = i
|
||||
return
|
||||
}
|
||||
bytes(ctx, ctx.partial[:], 256)
|
||||
|
||||
for (j + 32) < length {
|
||||
bytes(ctx, data[j:], 256)
|
||||
j += 32
|
||||
}
|
||||
|
||||
i = 0
|
||||
for j < length {
|
||||
ctx.partial[i] = data[j]
|
||||
i, j = i + 1, j + 1
|
||||
}
|
||||
ctx.partial_bytes = i
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Gost_Context, hash: []byte) {
|
||||
if ctx.partial_bytes > 0 {
|
||||
mem.set(&ctx.partial[ctx.partial_bytes], 0, 32 - int(ctx.partial_bytes))
|
||||
bytes(ctx, ctx.partial[:], u32(ctx.partial_bytes) << 3)
|
||||
}
|
||||
|
||||
compress(ctx.hash[:], ctx.len[:])
|
||||
compress(ctx.hash[:], ctx.sum[:])
|
||||
|
||||
for i, j := 0, 0; i < 8; i, j = i + 1, j + 4 {
|
||||
hash[j] = byte(ctx.hash[i])
|
||||
hash[j + 1] = byte(ctx.hash[i] >> 8)
|
||||
hash[j + 2] = byte(ctx.hash[i] >> 16)
|
||||
hash[j + 3] = byte(ctx.hash[i] >> 24)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
GOST implementation
|
||||
*/
|
||||
|
||||
Gost_Context :: struct {
|
||||
sum: [8]u32,
|
||||
hash: [8]u32,
|
||||
len: [8]u32,
|
||||
partial: [32]byte,
|
||||
partial_bytes: byte,
|
||||
}
|
||||
|
||||
SBOX_1: [256]u32
|
||||
SBOX_2: [256]u32
|
||||
SBOX_3: [256]u32
|
||||
SBOX_4: [256]u32
|
||||
|
||||
ENCRYPT_ROUND :: #force_inline proc "contextless" (l, r, t, k1, k2: u32) -> (u32, u32, u32) {
|
||||
l, r, t := l, r, t
|
||||
t = (k1) + r
|
||||
l ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24]
|
||||
t = (k2) + l
|
||||
r ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24]
|
||||
return l, r, t
|
||||
}
|
||||
|
||||
ENCRYPT :: #force_inline proc "contextless" (a, b, c: u32, key: []u32) -> (l, r, t: u32) {
|
||||
l, r, t = ENCRYPT_ROUND(a, b, c, key[0], key[1])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[7], key[6])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[5], key[4])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[3], key[2])
|
||||
l, r, t = ENCRYPT_ROUND(l, r, t, key[1], key[0])
|
||||
t = r
|
||||
r = l
|
||||
l = t
|
||||
return
|
||||
}
|
||||
|
||||
bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) {
|
||||
a, c: u32
|
||||
m: [8]u32
|
||||
|
||||
for i, j := 0, 0; i < 8; i += 1 {
|
||||
a = u32(buf[j]) | u32(buf[j + 1]) << 8 | u32(buf[j + 2]) << 16 | u32(buf[j + 3]) << 24
|
||||
j += 4
|
||||
m[i] = a
|
||||
c = a + c + ctx.sum[i]
|
||||
ctx.sum[i] = c
|
||||
c = c < a ? 1 : 0
|
||||
}
|
||||
|
||||
compress(ctx.hash[:], m[:])
|
||||
ctx.len[0] += bits
|
||||
if ctx.len[0] < bits {
|
||||
ctx.len[1] += 1
|
||||
}
|
||||
}
|
||||
|
||||
compress :: proc(h, m: []u32) {
|
||||
key, u, v, w, s: [8]u32
|
||||
|
||||
copy(u[:], h)
|
||||
copy(v[:], m)
|
||||
|
||||
for i := 0; i < 8; i += 2 {
|
||||
w[0] = u[0] ~ v[0]
|
||||
w[1] = u[1] ~ v[1]
|
||||
w[2] = u[2] ~ v[2]
|
||||
w[3] = u[3] ~ v[3]
|
||||
w[4] = u[4] ~ v[4]
|
||||
w[5] = u[5] ~ v[5]
|
||||
w[6] = u[6] ~ v[6]
|
||||
w[7] = u[7] ~ v[7]
|
||||
|
||||
key[0] = (w[0] & 0x000000ff) | (w[2] & 0x000000ff) << 8 | (w[4] & 0x000000ff) << 16 | (w[6] & 0x000000ff) << 24
|
||||
key[1] = (w[0] & 0x0000ff00) >> 8 | (w[2] & 0x0000ff00) | (w[4] & 0x0000ff00) << 8 | (w[6] & 0x0000ff00) << 16
|
||||
key[2] = (w[0] & 0x00ff0000) >> 16 | (w[2] & 0x00ff0000) >> 8 | (w[4] & 0x00ff0000) | (w[6] & 0x00ff0000) << 8
|
||||
key[3] = (w[0] & 0xff000000) >> 24 | (w[2] & 0xff000000) >> 16 | (w[4] & 0xff000000) >> 8 | (w[6] & 0xff000000)
|
||||
key[4] = (w[1] & 0x000000ff) | (w[3] & 0x000000ff) << 8 | (w[5] & 0x000000ff) << 16 | (w[7] & 0x000000ff) << 24
|
||||
key[5] = (w[1] & 0x0000ff00) >> 8 | (w[3] & 0x0000ff00) | (w[5] & 0x0000ff00) << 8 | (w[7] & 0x0000ff00) << 16
|
||||
key[6] = (w[1] & 0x00ff0000) >> 16 | (w[3] & 0x00ff0000) >> 8 | (w[5] & 0x00ff0000) | (w[7] & 0x00ff0000) << 8
|
||||
key[7] = (w[1] & 0xff000000) >> 24 | (w[3] & 0xff000000) >> 16 | (w[5] & 0xff000000) >> 8 | (w[7] & 0xff000000)
|
||||
|
||||
r := h[i]
|
||||
l := h[i + 1]
|
||||
t: u32
|
||||
l, r, t = ENCRYPT(l, r, 0, key[:])
|
||||
|
||||
s[i] = r
|
||||
s[i + 1] = l
|
||||
|
||||
if i == 6 {
|
||||
break
|
||||
}
|
||||
|
||||
l = u[0] ~ u[2]
|
||||
r = u[1] ~ u[3]
|
||||
u[0] = u[2]
|
||||
u[1] = u[3]
|
||||
u[2] = u[4]
|
||||
u[3] = u[5]
|
||||
u[4] = u[6]
|
||||
u[5] = u[7]
|
||||
u[6] = l
|
||||
u[7] = r
|
||||
|
||||
if i == 2 {
|
||||
u[0] ~= 0xff00ff00
|
||||
u[1] ~= 0xff00ff00
|
||||
u[2] ~= 0x00ff00ff
|
||||
u[3] ~= 0x00ff00ff
|
||||
u[4] ~= 0x00ffff00
|
||||
u[5] ~= 0xff0000ff
|
||||
u[6] ~= 0x000000ff
|
||||
u[7] ~= 0xff00ffff
|
||||
}
|
||||
|
||||
l = v[0]
|
||||
r = v[2]
|
||||
v[0] = v[4]
|
||||
v[2] = v[6]
|
||||
v[4] = l ~ r
|
||||
v[6] = v[0] ~ r
|
||||
l = v[1]
|
||||
r = v[3]
|
||||
v[1] = v[5]
|
||||
v[3] = v[7]
|
||||
v[5] = l ~ r
|
||||
v[7] = v[1] ~ r
|
||||
}
|
||||
|
||||
u[0] = m[0] ~ s[6]
|
||||
u[1] = m[1] ~ s[7]
|
||||
u[2] = m[2] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff) ~
|
||||
(s[1] & 0xffff) ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[6] ~ (s[6] << 16) ~
|
||||
(s[7] & 0xffff0000) ~ (s[7] >> 16)
|
||||
u[3] = m[3] ~ (s[0] & 0xffff) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~
|
||||
(s[1] << 16) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~
|
||||
(s[3] << 16) ~ s[6] ~ (s[6] << 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~
|
||||
(s[7] << 16) ~ (s[7] >> 16)
|
||||
u[4] = m[4] ~
|
||||
(s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[0] >> 16) ~
|
||||
(s[1] & 0xffff0000) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~
|
||||
(s[3] << 16) ~ (s[3] >> 16) ~ (s[4] << 16) ~ (s[6] << 16) ~
|
||||
(s[6] >> 16) ~(s[7] & 0xffff) ~ (s[7] << 16) ~ (s[7] >> 16)
|
||||
u[5] = m[5] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff0000) ~
|
||||
(s[1] & 0xffff) ~ s[2] ~ (s[2] >> 16) ~ (s[3] << 16) ~ (s[3] >> 16) ~
|
||||
(s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[6] << 16) ~
|
||||
(s[6] >> 16) ~ (s[7] & 0xffff0000) ~ (s[7] << 16) ~ (s[7] >> 16)
|
||||
u[6] = m[6] ~ s[0] ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[3] ~ (s[3] >> 16) ~
|
||||
(s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[5] >> 16) ~ s[6] ~
|
||||
(s[6] << 16) ~ (s[6] >> 16) ~ (s[7] << 16)
|
||||
u[7] = m[7] ~ (s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~
|
||||
(s[1] << 16) ~ (s[2] >> 16) ~ (s[3] << 16) ~ s[4] ~ (s[4] >> 16) ~
|
||||
(s[5] << 16) ~ (s[5] >> 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~
|
||||
(s[7] << 16) ~ (s[7] >> 16)
|
||||
|
||||
v[0] = h[0] ~ (u[1] << 16) ~ (u[0] >> 16)
|
||||
v[1] = h[1] ~ (u[2] << 16) ~ (u[1] >> 16)
|
||||
v[2] = h[2] ~ (u[3] << 16) ~ (u[2] >> 16)
|
||||
v[3] = h[3] ~ (u[4] << 16) ~ (u[3] >> 16)
|
||||
v[4] = h[4] ~ (u[5] << 16) ~ (u[4] >> 16)
|
||||
v[5] = h[5] ~ (u[6] << 16) ~ (u[5] >> 16)
|
||||
v[6] = h[6] ~ (u[7] << 16) ~ (u[6] >> 16)
|
||||
v[7] = h[7] ~ (u[0] & 0xffff0000) ~ (u[0] << 16) ~ (u[7] >> 16) ~ (u[1] & 0xffff0000) ~ (u[1] << 16) ~ (u[6] << 16) ~ (u[7] & 0xffff0000)
|
||||
|
||||
h[0] = (v[0] & 0xffff0000) ~ (v[0] << 16) ~ (v[0] >> 16) ~ (v[1] >> 16) ~
|
||||
(v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ (v[4] << 16) ~
|
||||
(v[5] >> 16) ~ v[5] ~ (v[6] >> 16) ~ (v[7] << 16) ~ (v[7] >> 16) ~
|
||||
(v[7] & 0xffff)
|
||||
h[1] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~ (v[1] & 0xffff) ~
|
||||
v[2] ~ (v[2] >> 16) ~ (v[3] << 16) ~ (v[4] >> 16) ~ (v[5] << 16) ~
|
||||
(v[6] << 16) ~ v[6] ~ (v[7] & 0xffff0000) ~ (v[7] >> 16)
|
||||
h[2] = (v[0] & 0xffff) ~ (v[0] << 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~
|
||||
(v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~
|
||||
(v[5] >> 16) ~ v[6] ~ (v[6] >> 16) ~ (v[7] & 0xffff) ~ (v[7] << 16) ~
|
||||
(v[7] >> 16)
|
||||
h[3] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~
|
||||
(v[1] & 0xffff0000) ~ (v[1] >> 16) ~ (v[2] << 16) ~ (v[2] >> 16) ~ v[2] ~
|
||||
(v[3] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~
|
||||
(v[7] & 0xffff) ~ (v[7] >> 16)
|
||||
h[4] = (v[0] >> 16) ~ (v[1] << 16) ~ v[1] ~ (v[2] >> 16) ~ v[2] ~
|
||||
(v[3] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ (v[5] >> 16) ~
|
||||
v[5] ~ (v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16)
|
||||
h[5] = (v[0] << 16) ~ (v[0] & 0xffff0000) ~ (v[1] << 16) ~ (v[1] >> 16) ~
|
||||
(v[1] & 0xffff0000) ~ (v[2] << 16) ~ v[2] ~ (v[3] >> 16) ~ v[3] ~
|
||||
(v[4] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~
|
||||
(v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ (v[7] >> 16) ~ (v[7] & 0xffff0000)
|
||||
h[6] = v[0] ~ v[2] ~ (v[2] >> 16) ~ v[3] ~ (v[3] << 16) ~ v[4] ~
|
||||
(v[4] >> 16) ~ (v[5] << 16) ~ (v[5] >> 16) ~ v[5] ~ (v[6] << 16) ~
|
||||
(v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ v[7]
|
||||
h[7] = v[0] ~ (v[0] >> 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~ (v[2] << 16) ~
|
||||
(v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ v[4] ~ (v[5] >> 16) ~ v[5] ~
|
||||
(v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16) ~ v[7]
|
||||
}
|
||||
@@ -0,0 +1,653 @@
|
||||
package groestl
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the GROESTL hashing algorithm, as defined in <http://www.groestl.info/Groestl.zip>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_224 :: 28
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_384 :: 48
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
|
||||
return hash_bytes_224(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 224
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_224 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 224
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_224 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 224
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_224 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_224(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_224(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_224]byte{}, false
|
||||
}
|
||||
|
||||
hash_224 :: proc {
|
||||
hash_stream_224,
|
||||
hash_file_224,
|
||||
hash_bytes_224,
|
||||
hash_string_224,
|
||||
hash_bytes_to_buffer_224,
|
||||
hash_string_to_buffer_224,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 256
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 256
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 256
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
|
||||
return hash_bytes_384(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 384
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_384 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 384
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_384 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 384
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_384 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_384(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_384(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_384]byte{}, false
|
||||
}
|
||||
|
||||
hash_384 :: proc {
|
||||
hash_stream_384,
|
||||
hash_file_384,
|
||||
hash_bytes_384,
|
||||
hash_string_384,
|
||||
hash_bytes_to_buffer_384,
|
||||
hash_string_to_buffer_384,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 512
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 512
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Groestl_Context
|
||||
ctx.hashbitlen = 512
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Groestl_Context) {
|
||||
assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
|
||||
if ctx.hashbitlen <= 256 {
|
||||
ctx.rounds = 10
|
||||
ctx.columns = 8
|
||||
ctx.statesize = 64
|
||||
} else {
|
||||
ctx.rounds = 14
|
||||
ctx.columns = 16
|
||||
ctx.statesize = 128
|
||||
}
|
||||
for i := 8 - size_of(i32); i < 8; i += 1 {
|
||||
ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i))))
|
||||
}
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Groestl_Context, data: []byte) {
|
||||
databitlen := len(data) * 8
|
||||
msglen := databitlen / 8
|
||||
rem := databitlen % 8
|
||||
|
||||
i: int
|
||||
assert(ctx.bits_in_last_byte == 0)
|
||||
|
||||
if ctx.buf_ptr != 0 {
|
||||
for i = 0; ctx.buf_ptr < ctx.statesize && i < msglen; i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 {
|
||||
ctx.buffer[ctx.buf_ptr] = data[i]
|
||||
}
|
||||
|
||||
if ctx.buf_ptr < ctx.statesize {
|
||||
if rem != 0 {
|
||||
ctx.bits_in_last_byte = rem
|
||||
ctx.buffer[ctx.buf_ptr] = data[i]
|
||||
ctx.buf_ptr += 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.buf_ptr = 0
|
||||
transform(ctx, ctx.buffer[:], u32(ctx.statesize))
|
||||
}
|
||||
|
||||
transform(ctx, data[i:], u32(msglen - i))
|
||||
i += ((msglen - i) / ctx.statesize) * ctx.statesize
|
||||
for i < msglen {
|
||||
ctx.buffer[ctx.buf_ptr] = data[i]
|
||||
i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1
|
||||
}
|
||||
|
||||
if rem != 0 {
|
||||
ctx.bits_in_last_byte = rem
|
||||
ctx.buffer[ctx.buf_ptr] = data[i]
|
||||
ctx.buf_ptr += 1
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Groestl_Context, hash: []byte) {
|
||||
hashbytelen := ctx.hashbitlen / 8
|
||||
|
||||
if ctx.bits_in_last_byte != 0 {
|
||||
ctx.buffer[ctx.buf_ptr - 1] &= ((1 << uint(ctx.bits_in_last_byte)) - 1) << (8 - uint(ctx.bits_in_last_byte))
|
||||
ctx.buffer[ctx.buf_ptr - 1] ~= 0x1 << (7 - uint(ctx.bits_in_last_byte))
|
||||
} else {
|
||||
ctx.buffer[ctx.buf_ptr] = 0x80
|
||||
ctx.buf_ptr += 1
|
||||
}
|
||||
|
||||
if ctx.buf_ptr > ctx.statesize - 8 {
|
||||
for ctx.buf_ptr < ctx.statesize {
|
||||
ctx.buffer[ctx.buf_ptr] = 0
|
||||
ctx.buf_ptr += 1
|
||||
}
|
||||
transform(ctx, ctx.buffer[:], u32(ctx.statesize))
|
||||
ctx.buf_ptr = 0
|
||||
}
|
||||
|
||||
for ctx.buf_ptr < ctx.statesize - 8 {
|
||||
ctx.buffer[ctx.buf_ptr] = 0
|
||||
ctx.buf_ptr += 1
|
||||
}
|
||||
|
||||
ctx.block_counter += 1
|
||||
ctx.buf_ptr = ctx.statesize
|
||||
|
||||
for ctx.buf_ptr > ctx.statesize - 8 {
|
||||
ctx.buf_ptr -= 1
|
||||
ctx.buffer[ctx.buf_ptr] = byte(ctx.block_counter)
|
||||
ctx.block_counter >>= 8
|
||||
}
|
||||
|
||||
transform(ctx, ctx.buffer[:], u32(ctx.statesize))
|
||||
output_transformation(ctx)
|
||||
|
||||
for i, j := ctx.statesize - hashbytelen , 0; i < ctx.statesize; i, j = i + 1, j + 1 {
|
||||
hash[j] = ctx.chaining[i % 8][i / 8]
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
GROESTL implementation
|
||||
*/
|
||||
|
||||
SBOX := [256]byte {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
|
||||
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
||||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
|
||||
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
||||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
|
||||
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
||||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
|
||||
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
||||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
|
||||
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
|
||||
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
}
|
||||
|
||||
SHIFT := [2][2][8]int {
|
||||
{{0, 1, 2, 3, 4, 5, 6, 7}, {1, 3, 5, 7, 0, 2, 4, 6}},
|
||||
{{0, 1, 2, 3, 4, 5, 6, 11}, {1, 3, 5, 11, 0, 2, 4, 6}},
|
||||
}
|
||||
|
||||
Groestl_Context :: struct {
|
||||
chaining: [8][16]byte,
|
||||
block_counter: u64,
|
||||
hashbitlen: int,
|
||||
buffer: [128]byte,
|
||||
buf_ptr: int,
|
||||
bits_in_last_byte: int,
|
||||
columns: int,
|
||||
rounds: int,
|
||||
statesize: int,
|
||||
}
|
||||
|
||||
Groestl_Variant :: enum {
|
||||
P512 = 0,
|
||||
Q512 = 1,
|
||||
P1024 = 2,
|
||||
Q1024 = 3,
|
||||
}
|
||||
|
||||
MUL2 :: #force_inline proc "contextless"(b: byte) -> byte {
|
||||
return (b >> 7) != 0 ? (b << 1) ~ 0x1b : (b << 1)
|
||||
}
|
||||
|
||||
MUL3 :: #force_inline proc "contextless"(b: byte) -> byte {
|
||||
return MUL2(b) ~ b
|
||||
}
|
||||
|
||||
MUL4 :: #force_inline proc "contextless"(b: byte) -> byte {
|
||||
return MUL2(MUL2(b))
|
||||
}
|
||||
|
||||
MUL5 :: #force_inline proc "contextless"(b: byte) -> byte {
|
||||
return MUL4(b) ~ b
|
||||
}
|
||||
|
||||
MUL6 :: #force_inline proc "contextless"(b: byte) -> byte {
|
||||
return MUL4(b) ~ MUL2(b)
|
||||
}
|
||||
|
||||
MUL7 :: #force_inline proc "contextless"(b: byte) -> byte {
|
||||
return MUL4(b) ~ MUL2(b) ~ b
|
||||
}
|
||||
|
||||
sub_bytes :: #force_inline proc (x: [][16]byte, columns: int) {
|
||||
for i := 0; i < 8; i += 1 {
|
||||
for j := 0; j < columns; j += 1 {
|
||||
x[i][j] = SBOX[x[i][j]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shift_bytes :: #force_inline proc (x: [][16]byte, columns: int, v: Groestl_Variant) {
|
||||
temp: [16]byte
|
||||
R := &SHIFT[int(v) / 2][int(v) & 1]
|
||||
|
||||
for i := 0; i < 8; i += 1 {
|
||||
for j := 0; j < columns; j += 1 {
|
||||
temp[j] = x[i][(j + R[i]) % columns]
|
||||
}
|
||||
for j := 0; j < columns; j += 1 {
|
||||
x[i][j] = temp[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mix_bytes :: #force_inline proc (x: [][16]byte, columns: int) {
|
||||
temp: [8]byte
|
||||
|
||||
for i := 0; i < columns; i += 1 {
|
||||
for j := 0; j < 8; j += 1 {
|
||||
temp[j] = MUL2(x[(j + 0) % 8][i]) ~
|
||||
MUL2(x[(j + 1) % 8][i]) ~
|
||||
MUL3(x[(j + 2) % 8][i]) ~
|
||||
MUL4(x[(j + 3) % 8][i]) ~
|
||||
MUL5(x[(j + 4) % 8][i]) ~
|
||||
MUL3(x[(j + 5) % 8][i]) ~
|
||||
MUL5(x[(j + 6) % 8][i]) ~
|
||||
MUL7(x[(j + 7) % 8][i])
|
||||
}
|
||||
for j := 0; j < 8; j += 1 {
|
||||
x[j][i] = temp[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) {
|
||||
v := ctx.columns == 8 ? Groestl_Variant.P512 : Groestl_Variant.P1024
|
||||
for i := 0; i < ctx.rounds; i += 1 {
|
||||
add_roundconstant(x, ctx.columns, byte(i), v)
|
||||
sub_bytes(x, ctx.columns)
|
||||
shift_bytes(x, ctx.columns, v)
|
||||
mix_bytes(x, ctx.columns)
|
||||
}
|
||||
}
|
||||
|
||||
q :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) {
|
||||
v := ctx.columns == 8 ? Groestl_Variant.Q512 : Groestl_Variant.Q1024
|
||||
for i := 0; i < ctx.rounds; i += 1 {
|
||||
add_roundconstant(x, ctx.columns, byte(i), v)
|
||||
sub_bytes(x, ctx.columns)
|
||||
shift_bytes(x, ctx.columns, v)
|
||||
mix_bytes(x, ctx.columns)
|
||||
}
|
||||
}
|
||||
|
||||
transform :: proc(ctx: ^Groestl_Context, input: []byte, msglen: u32) {
|
||||
tmp1, tmp2: [8][16]byte
|
||||
input, msglen := input, msglen
|
||||
|
||||
for msglen >= u32(ctx.statesize) {
|
||||
for i := 0; i < 8; i += 1 {
|
||||
for j := 0; j < ctx.columns; j += 1 {
|
||||
tmp1[i][j] = ctx.chaining[i][j] ~ input[j * 8 + i]
|
||||
tmp2[i][j] = input[j * 8 + i]
|
||||
}
|
||||
}
|
||||
|
||||
p(ctx, tmp1[:])
|
||||
q(ctx, tmp2[:])
|
||||
|
||||
for i := 0; i < 8; i += 1 {
|
||||
for j := 0; j < ctx.columns; j += 1 {
|
||||
ctx.chaining[i][j] ~= tmp1[i][j] ~ tmp2[i][j]
|
||||
}
|
||||
}
|
||||
|
||||
ctx.block_counter += 1
|
||||
msglen -= u32(ctx.statesize)
|
||||
input = input[ctx.statesize:]
|
||||
}
|
||||
}
|
||||
|
||||
output_transformation :: proc(ctx: ^Groestl_Context) {
|
||||
temp: [8][16]byte
|
||||
|
||||
for i := 0; i < 8; i += 1 {
|
||||
for j := 0; j < ctx.columns; j += 1 {
|
||||
temp[i][j] = ctx.chaining[i][j]
|
||||
}
|
||||
}
|
||||
|
||||
p(ctx, temp[:])
|
||||
|
||||
for i := 0; i < 8; i += 1 {
|
||||
for j := 0; j < ctx.columns; j += 1 {
|
||||
ctx.chaining[i][j] ~= temp[i][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_roundconstant :: proc(x: [][16]byte, columns: int, round: byte, v: Groestl_Variant) {
|
||||
switch (i32(v) & 1) {
|
||||
case 0:
|
||||
for i := 0; i < columns; i += 1 {
|
||||
x[0][i] ~= byte(i << 4) ~ round
|
||||
}
|
||||
case 1:
|
||||
for i := 0; i < columns; i += 1 {
|
||||
for j := 0; j < 7; j += 1 {
|
||||
x[j][i] ~= 0xff
|
||||
}
|
||||
}
|
||||
for i := 0; i < columns; i += 1 {
|
||||
x[7][i] ~= byte(i << 4) ~ 0xff ~ round
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,584 @@
|
||||
package jh
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the JH hashing algorithm, as defined in <https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_224 :: 28
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_384 :: 48
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
|
||||
return hash_bytes_224(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 224
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_224 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 224
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_224 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 224
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_224 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_224(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_224(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_224]byte{}, false
|
||||
}
|
||||
|
||||
hash_224 :: proc {
|
||||
hash_stream_224,
|
||||
hash_file_224,
|
||||
hash_bytes_224,
|
||||
hash_string_224,
|
||||
hash_bytes_to_buffer_224,
|
||||
hash_string_to_buffer_224,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 256
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 256
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 256
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
|
||||
return hash_bytes_384(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 384
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_384 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 384
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_384 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 384
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_384 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_384(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_384(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_384]byte{}, false
|
||||
}
|
||||
|
||||
hash_384 :: proc {
|
||||
hash_stream_384,
|
||||
hash_file_384,
|
||||
hash_bytes_384,
|
||||
hash_string_384,
|
||||
hash_bytes_to_buffer_384,
|
||||
hash_string_to_buffer_384,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 512
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 512
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Jh_Context
|
||||
ctx.hashbitlen = 512
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Jh_Context) {
|
||||
assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
|
||||
ctx.H[1] = byte(ctx.hashbitlen) & 0xff
|
||||
ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff
|
||||
F8(ctx)
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Jh_Context, data: []byte) {
|
||||
databitlen := u64(len(data)) * 8
|
||||
ctx.databitlen += databitlen
|
||||
i := u64(0)
|
||||
|
||||
if (ctx.buffer_size > 0) && ((ctx.buffer_size + databitlen) < 512) {
|
||||
if (databitlen & 7) == 0 {
|
||||
copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)])
|
||||
} else {
|
||||
copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3) + 1])
|
||||
}
|
||||
ctx.buffer_size += databitlen
|
||||
databitlen = 0
|
||||
}
|
||||
|
||||
if (ctx.buffer_size > 0 ) && ((ctx.buffer_size + databitlen) >= 512) {
|
||||
copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)])
|
||||
i = 64 - (ctx.buffer_size >> 3)
|
||||
databitlen = databitlen - (512 - ctx.buffer_size)
|
||||
F8(ctx)
|
||||
ctx.buffer_size = 0
|
||||
}
|
||||
|
||||
for databitlen >= 512 {
|
||||
copy(ctx.buffer[:], data[i:i + 64])
|
||||
F8(ctx)
|
||||
i += 64
|
||||
databitlen -= 512
|
||||
}
|
||||
|
||||
if databitlen > 0 {
|
||||
if (databitlen & 7) == 0 {
|
||||
copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3)])
|
||||
} else {
|
||||
copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3) + 1])
|
||||
}
|
||||
ctx.buffer_size = databitlen
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Jh_Context, hash: []byte) {
|
||||
if ctx.databitlen & 0x1ff == 0 {
|
||||
for i := 0; i < 64; i += 1 {
|
||||
ctx.buffer[i] = 0
|
||||
}
|
||||
ctx.buffer[0] = 0x80
|
||||
ctx.buffer[63] = byte(ctx.databitlen) & 0xff
|
||||
ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff
|
||||
ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff
|
||||
ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff
|
||||
ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff
|
||||
ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff
|
||||
ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff
|
||||
ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff
|
||||
F8(ctx)
|
||||
} else {
|
||||
if ctx.buffer_size & 7 == 0 {
|
||||
for i := (ctx.databitlen & 0x1ff) >> 3; i < 64; i += 1 {
|
||||
ctx.buffer[i] = 0
|
||||
}
|
||||
} else {
|
||||
for i := ((ctx.databitlen & 0x1ff) >> 3) + 1; i < 64; i += 1 {
|
||||
ctx.buffer[i] = 0
|
||||
}
|
||||
}
|
||||
ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7))
|
||||
F8(ctx)
|
||||
for i := 0; i < 64; i += 1 {
|
||||
ctx.buffer[i] = 0
|
||||
}
|
||||
ctx.buffer[63] = byte(ctx.databitlen) & 0xff
|
||||
ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff
|
||||
ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff
|
||||
ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff
|
||||
ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff
|
||||
ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff
|
||||
ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff
|
||||
ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff
|
||||
F8(ctx)
|
||||
}
|
||||
switch ctx.hashbitlen {
|
||||
case 224: copy(hash[:], ctx.H[100:128])
|
||||
case 256: copy(hash[:], ctx.H[96:128])
|
||||
case 384: copy(hash[:], ctx.H[80:128])
|
||||
case 512: copy(hash[:], ctx.H[64:128])
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
JH implementation
|
||||
*/
|
||||
|
||||
ROUNDCONSTANT_ZERO := [64]byte {
|
||||
0x6, 0xa, 0x0, 0x9, 0xe, 0x6, 0x6, 0x7,
|
||||
0xf, 0x3, 0xb, 0xc, 0xc, 0x9, 0x0, 0x8,
|
||||
0xb, 0x2, 0xf, 0xb, 0x1, 0x3, 0x6, 0x6,
|
||||
0xe, 0xa, 0x9, 0x5, 0x7, 0xd, 0x3, 0xe,
|
||||
0x3, 0xa, 0xd, 0xe, 0xc, 0x1, 0x7, 0x5,
|
||||
0x1, 0x2, 0x7, 0x7, 0x5, 0x0, 0x9, 0x9,
|
||||
0xd, 0xa, 0x2, 0xf, 0x5, 0x9, 0x0, 0xb,
|
||||
0x0, 0x6, 0x6, 0x7, 0x3, 0x2, 0x2, 0xa,
|
||||
}
|
||||
|
||||
SBOX := [2][16]byte {
|
||||
{9, 0, 4, 11, 13, 12, 3, 15, 1, 10, 2, 6, 7, 5, 8, 14},
|
||||
{3, 12, 6, 13, 5, 7, 1, 9, 15, 2, 0, 4, 11, 10, 14, 8},
|
||||
}
|
||||
|
||||
Jh_Context :: struct {
|
||||
hashbitlen: int,
|
||||
databitlen: u64,
|
||||
buffer_size: u64,
|
||||
H: [128]byte,
|
||||
A: [256]byte,
|
||||
roundconstant: [64]byte,
|
||||
buffer: [64]byte,
|
||||
}
|
||||
|
||||
E8_finaldegroup :: proc(ctx: ^Jh_Context) {
|
||||
t0,t1,t2,t3: byte
|
||||
tem: [256]byte
|
||||
for i := 0; i < 128; i += 1 {
|
||||
tem[i] = ctx.A[i << 1]
|
||||
tem[i + 128] = ctx.A[(i << 1) + 1]
|
||||
}
|
||||
for i := 0; i < 128; i += 1 {
|
||||
ctx.H[i] = 0
|
||||
}
|
||||
for i := 0; i < 256; i += 1 {
|
||||
t0 = (tem[i] >> 3) & 1
|
||||
t1 = (tem[i] >> 2) & 1
|
||||
t2 = (tem[i] >> 1) & 1
|
||||
t3 = (tem[i] >> 0) & 1
|
||||
|
||||
ctx.H[uint(i) >> 3] |= t0 << (7 - (uint(i) & 7))
|
||||
ctx.H[(uint(i) + 256) >> 3] |= t1 << (7 - (uint(i) & 7))
|
||||
ctx.H[(uint(i) + 512) >> 3] |= t2 << (7 - (uint(i) & 7))
|
||||
ctx.H[(uint(i) + 768) >> 3] |= t3 << (7 - (uint(i) & 7))
|
||||
}
|
||||
}
|
||||
|
||||
update_roundconstant :: proc(ctx: ^Jh_Context) {
|
||||
tem: [64]byte
|
||||
t: byte
|
||||
for i := 0; i < 64; i += 1 {
|
||||
tem[i] = SBOX[0][ctx.roundconstant[i]]
|
||||
}
|
||||
for i := 0; i < 64; i += 2 {
|
||||
tem[i + 1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf
|
||||
tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf
|
||||
}
|
||||
for i := 0; i < 64; i += 4 {
|
||||
t = tem[i + 2]
|
||||
tem[i + 2] = tem[i + 3]
|
||||
tem[i + 3] = t
|
||||
}
|
||||
for i := 0; i < 32; i += 1 {
|
||||
ctx.roundconstant[i] = tem[i << 1]
|
||||
ctx.roundconstant[i + 32] = tem[(i << 1) + 1]
|
||||
}
|
||||
for i := 32; i < 64; i += 2 {
|
||||
t = ctx.roundconstant[i]
|
||||
ctx.roundconstant[i] = ctx.roundconstant[i + 1]
|
||||
ctx.roundconstant[i + 1] = t
|
||||
}
|
||||
}
|
||||
|
||||
R8 :: proc(ctx: ^Jh_Context) {
|
||||
t: byte
|
||||
tem, roundconstant_expanded: [256]byte
|
||||
for i := u32(0); i < 256; i += 1 {
|
||||
roundconstant_expanded[i] = (ctx.roundconstant[i >> 2] >> (3 - (i & 3)) ) & 1
|
||||
}
|
||||
for i := 0; i < 256; i += 1 {
|
||||
tem[i] = SBOX[roundconstant_expanded[i]][ctx.A[i]]
|
||||
}
|
||||
for i := 0; i < 256; i += 2 {
|
||||
tem[i+1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf
|
||||
tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf
|
||||
}
|
||||
for i := 0; i < 256; i += 4 {
|
||||
t = tem[i + 2]
|
||||
tem[i+2] = tem[i + 3]
|
||||
tem[i+3] = t
|
||||
}
|
||||
for i := 0; i < 128; i += 1 {
|
||||
ctx.A[i] = tem[i << 1]
|
||||
ctx.A[i + 128] = tem[(i << 1) + 1]
|
||||
}
|
||||
for i := 128; i < 256; i += 2 {
|
||||
t = ctx.A[i]
|
||||
ctx.A[i] = ctx.A[i + 1]
|
||||
ctx.A[i + 1] = t
|
||||
}
|
||||
}
|
||||
|
||||
E8_initialgroup :: proc(ctx: ^Jh_Context) {
|
||||
t0, t1, t2, t3: byte
|
||||
tem: [256]byte
|
||||
for i := u32(0); i < 256; i += 1 {
|
||||
t0 = (ctx.H[i >> 3] >> (7 - (i & 7))) & 1
|
||||
t1 = (ctx.H[(i + 256) >> 3] >> (7 - (i & 7))) & 1
|
||||
t2 = (ctx.H[(i + 512) >> 3] >> (7 - (i & 7))) & 1
|
||||
t3 = (ctx.H[(i + 768) >> 3] >> (7 - (i & 7))) & 1
|
||||
tem[i] = (t0 << 3) | (t1 << 2) | (t2 << 1) | (t3 << 0)
|
||||
}
|
||||
for i := 0; i < 128; i += 1 {
|
||||
ctx.A[i << 1] = tem[i]
|
||||
ctx.A[(i << 1) + 1] = tem[i + 128]
|
||||
}
|
||||
}
|
||||
|
||||
E8 :: proc(ctx: ^Jh_Context) {
|
||||
for i := 0; i < 64; i += 1 {
|
||||
ctx.roundconstant[i] = ROUNDCONSTANT_ZERO[i]
|
||||
}
|
||||
E8_initialgroup(ctx)
|
||||
for i := 0; i < 42; i += 1 {
|
||||
R8(ctx)
|
||||
update_roundconstant(ctx)
|
||||
}
|
||||
E8_finaldegroup(ctx)
|
||||
}
|
||||
|
||||
F8 :: proc(ctx: ^Jh_Context) {
|
||||
for i := 0; i < 64; i += 1 {
|
||||
ctx.H[i] ~= ctx.buffer[i]
|
||||
}
|
||||
E8(ctx)
|
||||
for i := 0; i < 64; i += 1 {
|
||||
ctx.H[i + 64] ~= ctx.buffer[i]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
package keccak
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the Keccak hashing algorithm.
|
||||
This is done because the padding in the SHA3 standard was changed by the NIST, resulting in a different output.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../_sha3"
|
||||
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_224 :: 28
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_384 :: 48
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
|
||||
return hash_bytes_224(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_224 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_224 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_224 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_224(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_224(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_224]byte{}, false
|
||||
}
|
||||
|
||||
hash_224 :: proc {
|
||||
hash_stream_224,
|
||||
hash_file_224,
|
||||
hash_bytes_224,
|
||||
hash_string_224,
|
||||
hash_bytes_to_buffer_224,
|
||||
hash_string_to_buffer_224,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
|
||||
return hash_bytes_384(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_384 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_384 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_384 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_384(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_384(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_384]byte{}, false
|
||||
}
|
||||
|
||||
hash_384 :: proc {
|
||||
hash_stream_384,
|
||||
hash_file_384,
|
||||
hash_bytes_384,
|
||||
hash_string_384,
|
||||
hash_bytes_to_buffer_384,
|
||||
hash_string_to_buffer_384,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Keccak_Context :: _sha3.Sha3_Context
|
||||
|
||||
init :: proc(ctx: ^_sha3.Sha3_Context) {
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
|
||||
_sha3.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
|
||||
_sha3.final(ctx, hash)
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package md2
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the MD2 hashing algorithm, as defined in RFC 1319 <https://datatracker.ietf.org/doc/html/rfc1319>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 16
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Md2_Context
|
||||
// init(&ctx) No-op
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Md2_Context
|
||||
// init(&ctx) No-op
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Md2_Context
|
||||
// init(&ctx) No-op
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
@(warning="Init is a no-op for MD2")
|
||||
init :: proc(ctx: ^Md2_Context) {
|
||||
// No action needed here
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Md2_Context, data: []byte) {
|
||||
for i := 0; i < len(data); i += 1 {
|
||||
ctx.data[ctx.datalen] = data[i]
|
||||
ctx.datalen += 1
|
||||
if (ctx.datalen == DIGEST_SIZE) {
|
||||
transform(ctx, ctx.data[:])
|
||||
ctx.datalen = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Md2_Context, hash: []byte) {
|
||||
to_pad := byte(DIGEST_SIZE - ctx.datalen)
|
||||
for ctx.datalen < DIGEST_SIZE {
|
||||
ctx.data[ctx.datalen] = to_pad
|
||||
ctx.datalen += 1
|
||||
}
|
||||
transform(ctx, ctx.data[:])
|
||||
transform(ctx, ctx.checksum[:])
|
||||
for i := 0; i < DIGEST_SIZE; i += 1 {
|
||||
hash[i] = ctx.state[i]
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MD2 implementation
|
||||
*/
|
||||
|
||||
Md2_Context :: struct {
|
||||
data: [DIGEST_SIZE]byte,
|
||||
state: [DIGEST_SIZE * 3]byte,
|
||||
checksum: [DIGEST_SIZE]byte,
|
||||
datalen: int,
|
||||
}
|
||||
|
||||
PI_TABLE := [?]byte {
|
||||
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
|
||||
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76,
|
||||
130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138,
|
||||
23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142,
|
||||
187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16,
|
||||
137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62,
|
||||
204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215,
|
||||
94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182,
|
||||
118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135,
|
||||
32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176,
|
||||
185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221,
|
||||
81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110,
|
||||
133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55,
|
||||
200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136,
|
||||
149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242,
|
||||
239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
|
||||
49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131,
|
||||
20,
|
||||
}
|
||||
|
||||
transform :: proc(ctx: ^Md2_Context, data: []byte) {
|
||||
j,k,t: byte
|
||||
for j = 0; j < DIGEST_SIZE; j += 1 {
|
||||
ctx.state[j + DIGEST_SIZE] = data[j]
|
||||
ctx.state[j + DIGEST_SIZE * 2] = (ctx.state[j + DIGEST_SIZE] ~ ctx.state[j])
|
||||
}
|
||||
t = 0
|
||||
for j = 0; j < DIGEST_SIZE + 2; j += 1 {
|
||||
for k = 0; k < DIGEST_SIZE * 3; k += 1 {
|
||||
ctx.state[k] ~= PI_TABLE[t]
|
||||
t = ctx.state[k]
|
||||
}
|
||||
t = (t + j) & 0xff
|
||||
}
|
||||
t = ctx.checksum[DIGEST_SIZE - 1]
|
||||
for j = 0; j < DIGEST_SIZE; j += 1 {
|
||||
ctx.checksum[j] ~= PI_TABLE[data[j] ~ t]
|
||||
t = ctx.checksum[j]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
package md4
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings.
|
||||
|
||||
Implementation of the MD4 hashing algorithm, as defined in RFC 1320 <https://datatracker.ietf.org/doc/html/rfc1320>
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 16
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Md4_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Md4_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Md4_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Md4_Context) {
|
||||
ctx.state[0] = 0x67452301
|
||||
ctx.state[1] = 0xefcdab89
|
||||
ctx.state[2] = 0x98badcfe
|
||||
ctx.state[3] = 0x10325476
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Md4_Context, data: []byte) {
|
||||
for i := 0; i < len(data); i += 1 {
|
||||
ctx.data[ctx.datalen] = data[i]
|
||||
ctx.datalen += 1
|
||||
if(ctx.datalen == BLOCK_SIZE) {
|
||||
transform(ctx, ctx.data[:])
|
||||
ctx.bitlen += 512
|
||||
ctx.datalen = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Md4_Context, hash: []byte) {
|
||||
i := ctx.datalen
|
||||
if ctx.datalen < 56 {
|
||||
ctx.data[i] = 0x80
|
||||
i += 1
|
||||
for i < 56 {
|
||||
ctx.data[i] = 0x00
|
||||
i += 1
|
||||
}
|
||||
} else if ctx.datalen >= 56 {
|
||||
ctx.data[i] = 0x80
|
||||
i += 1
|
||||
for i < BLOCK_SIZE {
|
||||
ctx.data[i] = 0x00
|
||||
i += 1
|
||||
}
|
||||
transform(ctx, ctx.data[:])
|
||||
mem.set(&ctx.data, 0, 56)
|
||||
}
|
||||
|
||||
ctx.bitlen += u64(ctx.datalen * 8)
|
||||
ctx.data[56] = byte(ctx.bitlen)
|
||||
ctx.data[57] = byte(ctx.bitlen >> 8)
|
||||
ctx.data[58] = byte(ctx.bitlen >> 16)
|
||||
ctx.data[59] = byte(ctx.bitlen >> 24)
|
||||
ctx.data[60] = byte(ctx.bitlen >> 32)
|
||||
ctx.data[61] = byte(ctx.bitlen >> 40)
|
||||
ctx.data[62] = byte(ctx.bitlen >> 48)
|
||||
ctx.data[63] = byte(ctx.bitlen >> 56)
|
||||
transform(ctx, ctx.data[:])
|
||||
|
||||
for i = 0; i < 4; i += 1 {
|
||||
hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff
|
||||
hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff
|
||||
hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff
|
||||
hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MD4 implementation
|
||||
*/
|
||||
|
||||
BLOCK_SIZE :: 64
|
||||
|
||||
Md4_Context :: struct {
|
||||
data: [64]byte,
|
||||
state: [4]u32,
|
||||
bitlen: u64,
|
||||
datalen: u32,
|
||||
}
|
||||
|
||||
/*
|
||||
@note(zh): F, G and H, as mentioned in the RFC, have been inlined into FF, GG
|
||||
and HH respectively, instead of declaring them separately.
|
||||
*/
|
||||
|
||||
FF :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 {
|
||||
return util.ROTL32(a + ((b & c) | (~b & d)) + x, s)
|
||||
}
|
||||
|
||||
GG :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 {
|
||||
return util.ROTL32(a + ((b & c) | (b & d) | (c & d)) + x + 0x5a827999, s)
|
||||
}
|
||||
|
||||
HH :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 {
|
||||
return util.ROTL32(a + (b ~ c ~ d) + x + 0x6ed9eba1, s)
|
||||
}
|
||||
|
||||
transform :: proc(ctx: ^Md4_Context, data: []byte) {
|
||||
a, b, c, d, i, j: u32
|
||||
m: [DIGEST_SIZE]u32
|
||||
|
||||
for i, j = 0, 0; i < DIGEST_SIZE; i += 1 {
|
||||
m[i] = u32(data[j]) | (u32(data[j + 1]) << 8) | (u32(data[j + 2]) << 16) | (u32(data[j + 3]) << 24)
|
||||
j += 4
|
||||
}
|
||||
|
||||
a = ctx.state[0]
|
||||
b = ctx.state[1]
|
||||
c = ctx.state[2]
|
||||
d = ctx.state[3]
|
||||
|
||||
a = FF(a, b, c, d, m[0], 3)
|
||||
d = FF(d, a, b, c, m[1], 7)
|
||||
c = FF(c, d, a, b, m[2], 11)
|
||||
b = FF(b, c, d, a, m[3], 19)
|
||||
a = FF(a, b, c, d, m[4], 3)
|
||||
d = FF(d, a, b, c, m[5], 7)
|
||||
c = FF(c, d, a, b, m[6], 11)
|
||||
b = FF(b, c, d, a, m[7], 19)
|
||||
a = FF(a, b, c, d, m[8], 3)
|
||||
d = FF(d, a, b, c, m[9], 7)
|
||||
c = FF(c, d, a, b, m[10], 11)
|
||||
b = FF(b, c, d, a, m[11], 19)
|
||||
a = FF(a, b, c, d, m[12], 3)
|
||||
d = FF(d, a, b, c, m[13], 7)
|
||||
c = FF(c, d, a, b, m[14], 11)
|
||||
b = FF(b, c, d, a, m[15], 19)
|
||||
|
||||
a = GG(a, b, c, d, m[0], 3)
|
||||
d = GG(d, a, b, c, m[4], 5)
|
||||
c = GG(c, d, a, b, m[8], 9)
|
||||
b = GG(b, c, d, a, m[12], 13)
|
||||
a = GG(a, b, c, d, m[1], 3)
|
||||
d = GG(d, a, b, c, m[5], 5)
|
||||
c = GG(c, d, a, b, m[9], 9)
|
||||
b = GG(b, c, d, a, m[13], 13)
|
||||
a = GG(a, b, c, d, m[2], 3)
|
||||
d = GG(d, a, b, c, m[6], 5)
|
||||
c = GG(c, d, a, b, m[10], 9)
|
||||
b = GG(b, c, d, a, m[14], 13)
|
||||
a = GG(a, b, c, d, m[3], 3)
|
||||
d = GG(d, a, b, c, m[7], 5)
|
||||
c = GG(c, d, a, b, m[11], 9)
|
||||
b = GG(b, c, d, a, m[15], 13)
|
||||
|
||||
a = HH(a, b, c, d, m[0], 3)
|
||||
d = HH(d, a, b, c, m[8], 9)
|
||||
c = HH(c, d, a, b, m[4], 11)
|
||||
b = HH(b, c, d, a, m[12], 15)
|
||||
a = HH(a, b, c, d, m[2], 3)
|
||||
d = HH(d, a, b, c, m[10], 9)
|
||||
c = HH(c, d, a, b, m[6], 11)
|
||||
b = HH(b, c, d, a, m[14], 15)
|
||||
a = HH(a, b, c, d, m[1], 3)
|
||||
d = HH(d, a, b, c, m[9], 9)
|
||||
c = HH(c, d, a, b, m[5], 11)
|
||||
b = HH(b, c, d, a, m[13], 15)
|
||||
a = HH(a, b, c, d, m[3], 3)
|
||||
d = HH(d, a, b, c, m[11], 9)
|
||||
c = HH(c, d, a, b, m[7], 11)
|
||||
b = HH(b, c, d, a, m[15], 15)
|
||||
|
||||
ctx.state[0] += a
|
||||
ctx.state[1] += b
|
||||
ctx.state[2] += c
|
||||
ctx.state[3] += d
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
package md5
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the MD5 hashing algorithm, as defined in RFC 1321 <https://datatracker.ietf.org/doc/html/rfc1321>
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 16
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Md5_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Md5_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Md5_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Md5_Context) {
|
||||
ctx.state[0] = 0x67452301
|
||||
ctx.state[1] = 0xefcdab89
|
||||
ctx.state[2] = 0x98badcfe
|
||||
ctx.state[3] = 0x10325476
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Md5_Context, data: []byte) {
|
||||
for i := 0; i < len(data); i += 1 {
|
||||
ctx.data[ctx.datalen] = data[i]
|
||||
ctx.datalen += 1
|
||||
if(ctx.datalen == BLOCK_SIZE) {
|
||||
transform(ctx, ctx.data[:])
|
||||
ctx.bitlen += 512
|
||||
ctx.datalen = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Md5_Context, hash: []byte){
|
||||
i : u32
|
||||
i = ctx.datalen
|
||||
|
||||
if ctx.datalen < 56 {
|
||||
ctx.data[i] = 0x80
|
||||
i += 1
|
||||
for i < 56 {
|
||||
ctx.data[i] = 0x00
|
||||
i += 1
|
||||
}
|
||||
} else if ctx.datalen >= 56 {
|
||||
ctx.data[i] = 0x80
|
||||
i += 1
|
||||
for i < BLOCK_SIZE {
|
||||
ctx.data[i] = 0x00
|
||||
i += 1
|
||||
}
|
||||
transform(ctx, ctx.data[:])
|
||||
mem.set(&ctx.data, 0, 56)
|
||||
}
|
||||
|
||||
ctx.bitlen += u64(ctx.datalen * 8)
|
||||
ctx.data[56] = byte(ctx.bitlen)
|
||||
ctx.data[57] = byte(ctx.bitlen >> 8)
|
||||
ctx.data[58] = byte(ctx.bitlen >> 16)
|
||||
ctx.data[59] = byte(ctx.bitlen >> 24)
|
||||
ctx.data[60] = byte(ctx.bitlen >> 32)
|
||||
ctx.data[61] = byte(ctx.bitlen >> 40)
|
||||
ctx.data[62] = byte(ctx.bitlen >> 48)
|
||||
ctx.data[63] = byte(ctx.bitlen >> 56)
|
||||
transform(ctx, ctx.data[:])
|
||||
|
||||
for i = 0; i < 4; i += 1 {
|
||||
hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff
|
||||
hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff
|
||||
hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff
|
||||
hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MD4 implementation
|
||||
*/
|
||||
|
||||
BLOCK_SIZE :: 64
|
||||
|
||||
Md5_Context :: struct {
|
||||
data: [BLOCK_SIZE]byte,
|
||||
state: [4]u32,
|
||||
bitlen: u64,
|
||||
datalen: u32,
|
||||
}
|
||||
|
||||
/*
|
||||
@note(zh): F, G, H and I, as mentioned in the RFC, have been inlined into FF, GG, HH
|
||||
and II respectively, instead of declaring them separately.
|
||||
*/
|
||||
|
||||
FF :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + util.ROTL32(a + ((b & c) | (~b & d)) + m + t, s)
|
||||
}
|
||||
|
||||
GG :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + util.ROTL32(a + ((b & d) | (c & ~d)) + m + t, s)
|
||||
}
|
||||
|
||||
HH :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + util.ROTL32(a + (b ~ c ~ d) + m + t, s)
|
||||
}
|
||||
|
||||
II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + util.ROTL32(a + (c ~ (b | ~d)) + m + t, s)
|
||||
}
|
||||
|
||||
transform :: proc(ctx: ^Md5_Context, data: []byte) {
|
||||
i, j: u32
|
||||
m: [DIGEST_SIZE]u32
|
||||
|
||||
for i, j = 0, 0; i < DIGEST_SIZE; i+=1 {
|
||||
m[i] = u32(data[j]) + u32(data[j + 1]) << 8 + u32(data[j + 2]) << 16 + u32(data[j + 3]) << 24
|
||||
j += 4
|
||||
}
|
||||
|
||||
a := ctx.state[0]
|
||||
b := ctx.state[1]
|
||||
c := ctx.state[2]
|
||||
d := ctx.state[3]
|
||||
|
||||
a = FF(a, b, c, d, m[0], 7, 0xd76aa478)
|
||||
d = FF(d, a, b, c, m[1], 12, 0xe8c7b756)
|
||||
c = FF(c, d, a, b, m[2], 17, 0x242070db)
|
||||
b = FF(b, c, d, a, m[3], 22, 0xc1bdceee)
|
||||
a = FF(a, b, c, d, m[4], 7, 0xf57c0faf)
|
||||
d = FF(d, a, b, c, m[5], 12, 0x4787c62a)
|
||||
c = FF(c, d, a, b, m[6], 17, 0xa8304613)
|
||||
b = FF(b, c, d, a, m[7], 22, 0xfd469501)
|
||||
a = FF(a, b, c, d, m[8], 7, 0x698098d8)
|
||||
d = FF(d, a, b, c, m[9], 12, 0x8b44f7af)
|
||||
c = FF(c, d, a, b, m[10], 17, 0xffff5bb1)
|
||||
b = FF(b, c, d, a, m[11], 22, 0x895cd7be)
|
||||
a = FF(a, b, c, d, m[12], 7, 0x6b901122)
|
||||
d = FF(d, a, b, c, m[13], 12, 0xfd987193)
|
||||
c = FF(c, d, a, b, m[14], 17, 0xa679438e)
|
||||
b = FF(b, c, d, a, m[15], 22, 0x49b40821)
|
||||
|
||||
a = GG(a, b, c, d, m[1], 5, 0xf61e2562)
|
||||
d = GG(d, a, b, c, m[6], 9, 0xc040b340)
|
||||
c = GG(c, d, a, b, m[11], 14, 0x265e5a51)
|
||||
b = GG(b, c, d, a, m[0], 20, 0xe9b6c7aa)
|
||||
a = GG(a, b, c, d, m[5], 5, 0xd62f105d)
|
||||
d = GG(d, a, b, c, m[10], 9, 0x02441453)
|
||||
c = GG(c, d, a, b, m[15], 14, 0xd8a1e681)
|
||||
b = GG(b, c, d, a, m[4], 20, 0xe7d3fbc8)
|
||||
a = GG(a, b, c, d, m[9], 5, 0x21e1cde6)
|
||||
d = GG(d, a, b, c, m[14], 9, 0xc33707d6)
|
||||
c = GG(c, d, a, b, m[3], 14, 0xf4d50d87)
|
||||
b = GG(b, c, d, a, m[8], 20, 0x455a14ed)
|
||||
a = GG(a, b, c, d, m[13], 5, 0xa9e3e905)
|
||||
d = GG(d, a, b, c, m[2], 9, 0xfcefa3f8)
|
||||
c = GG(c, d, a, b, m[7], 14, 0x676f02d9)
|
||||
b = GG(b, c, d, a, m[12], 20, 0x8d2a4c8a)
|
||||
|
||||
a = HH(a, b, c, d, m[5], 4, 0xfffa3942)
|
||||
d = HH(d, a, b, c, m[8], 11, 0x8771f681)
|
||||
c = HH(c, d, a, b, m[11], 16, 0x6d9d6122)
|
||||
b = HH(b, c, d, a, m[14], 23, 0xfde5380c)
|
||||
a = HH(a, b, c, d, m[1], 4, 0xa4beea44)
|
||||
d = HH(d, a, b, c, m[4], 11, 0x4bdecfa9)
|
||||
c = HH(c, d, a, b, m[7], 16, 0xf6bb4b60)
|
||||
b = HH(b, c, d, a, m[10], 23, 0xbebfbc70)
|
||||
a = HH(a, b, c, d, m[13], 4, 0x289b7ec6)
|
||||
d = HH(d, a, b, c, m[0], 11, 0xeaa127fa)
|
||||
c = HH(c, d, a, b, m[3], 16, 0xd4ef3085)
|
||||
b = HH(b, c, d, a, m[6], 23, 0x04881d05)
|
||||
a = HH(a, b, c, d, m[9], 4, 0xd9d4d039)
|
||||
d = HH(d, a, b, c, m[12], 11, 0xe6db99e5)
|
||||
c = HH(c, d, a, b, m[15], 16, 0x1fa27cf8)
|
||||
b = HH(b, c, d, a, m[2], 23, 0xc4ac5665)
|
||||
|
||||
a = II(a, b, c, d, m[0], 6, 0xf4292244)
|
||||
d = II(d, a, b, c, m[7], 10, 0x432aff97)
|
||||
c = II(c, d, a, b, m[14], 15, 0xab9423a7)
|
||||
b = II(b, c, d, a, m[5], 21, 0xfc93a039)
|
||||
a = II(a, b, c, d, m[12], 6, 0x655b59c3)
|
||||
d = II(d, a, b, c, m[3], 10, 0x8f0ccc92)
|
||||
c = II(c, d, a, b, m[10], 15, 0xffeff47d)
|
||||
b = II(b, c, d, a, m[1], 21, 0x85845dd1)
|
||||
a = II(a, b, c, d, m[8], 6, 0x6fa87e4f)
|
||||
d = II(d, a, b, c, m[15], 10, 0xfe2ce6e0)
|
||||
c = II(c, d, a, b, m[6], 15, 0xa3014314)
|
||||
b = II(b, c, d, a, m[13], 21, 0x4e0811a1)
|
||||
a = II(a, b, c, d, m[4], 6, 0xf7537e82)
|
||||
d = II(d, a, b, c, m[11], 10, 0xbd3af235)
|
||||
c = II(c, d, a, b, m[2], 15, 0x2ad7d2bb)
|
||||
b = II(b, c, d, a, m[9], 21, 0xeb86d391)
|
||||
|
||||
ctx.state[0] += a
|
||||
ctx.state[1] += b
|
||||
ctx.state[2] += c
|
||||
ctx.state[3] += d
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package poly1305
|
||||
|
||||
import "core:crypto"
|
||||
import "core:crypto/util"
|
||||
import field "core:crypto/_fiat/field_poly1305"
|
||||
import "core:mem"
|
||||
|
||||
KEY_SIZE :: 32
|
||||
TAG_SIZE :: 16
|
||||
|
||||
_BLOCK_SIZE :: 16
|
||||
|
||||
sum :: proc (dst, msg, key: []byte) {
|
||||
ctx: Context = ---
|
||||
|
||||
init(&ctx, key)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, dst)
|
||||
}
|
||||
|
||||
verify :: proc (tag, msg, key: []byte) -> bool {
|
||||
ctx: Context = ---
|
||||
derived_tag: [16]byte = ---
|
||||
|
||||
if len(tag) != TAG_SIZE {
|
||||
panic("crypto/poly1305: invalid tag size")
|
||||
}
|
||||
|
||||
init(&ctx, key)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, derived_tag[:])
|
||||
|
||||
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||
}
|
||||
|
||||
Context :: struct {
|
||||
_r: field.Tight_Field_Element,
|
||||
_a: field.Tight_Field_Element,
|
||||
_s: field.Tight_Field_Element,
|
||||
|
||||
_buffer: [_BLOCK_SIZE]byte,
|
||||
_leftover: int,
|
||||
|
||||
_is_initialized: bool,
|
||||
}
|
||||
|
||||
init :: proc (ctx: ^Context, key: []byte) {
|
||||
if len(key) != KEY_SIZE {
|
||||
panic("crypto/poly1305: invalid key size")
|
||||
}
|
||||
|
||||
// r = le_bytes_to_num(key[0..15])
|
||||
// r = clamp(r) (r &= 0xffffffc0ffffffc0ffffffc0fffffff)
|
||||
tmp_lo := util.U64_LE(key[0:8]) & 0x0ffffffc0fffffff
|
||||
tmp_hi := util.U64_LE(key[8:16]) & 0xffffffc0ffffffc
|
||||
field.fe_from_u64s(&ctx._r, tmp_lo, tmp_hi)
|
||||
|
||||
// s = le_bytes_to_num(key[16..31])
|
||||
field.fe_from_bytes(&ctx._s, key[16:32], 0)
|
||||
|
||||
// a = 0
|
||||
field.fe_zero(&ctx._a)
|
||||
|
||||
// No leftover in buffer
|
||||
ctx._leftover = 0
|
||||
|
||||
ctx._is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc (ctx: ^Context, data: []byte) {
|
||||
assert(ctx._is_initialized)
|
||||
|
||||
msg := data
|
||||
msg_len := len(data)
|
||||
|
||||
// Handle leftover
|
||||
if ctx._leftover > 0 {
|
||||
want := min(_BLOCK_SIZE - ctx._leftover, msg_len)
|
||||
copy_slice(ctx._buffer[ctx._leftover:], msg[:want])
|
||||
msg_len = msg_len - want
|
||||
msg = msg[want:]
|
||||
ctx._leftover = ctx._leftover + want
|
||||
if ctx._leftover < _BLOCK_SIZE {
|
||||
return
|
||||
}
|
||||
_blocks(ctx, ctx._buffer[:])
|
||||
ctx._leftover = 0
|
||||
}
|
||||
|
||||
// Process full blocks
|
||||
if msg_len >= _BLOCK_SIZE {
|
||||
want := msg_len & (~int(_BLOCK_SIZE - 1))
|
||||
_blocks(ctx, msg[:want])
|
||||
msg = msg[want:]
|
||||
msg_len = msg_len - want
|
||||
}
|
||||
|
||||
// Store leftover
|
||||
if msg_len > 0 {
|
||||
// TODO: While -donna does it this way, I'm fairly sure that
|
||||
// `ctx._leftover == 0` is an invariant at this point.
|
||||
copy(ctx._buffer[ctx._leftover:], msg)
|
||||
ctx._leftover = ctx._leftover + msg_len
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc (ctx: ^Context, dst: []byte) {
|
||||
assert(ctx._is_initialized)
|
||||
|
||||
if len(dst) != TAG_SIZE {
|
||||
panic("poly1305: invalid destination tag size")
|
||||
}
|
||||
|
||||
// Process remaining block
|
||||
if ctx._leftover > 0 {
|
||||
ctx._buffer[ctx._leftover] = 1
|
||||
for i := ctx._leftover + 1; i < _BLOCK_SIZE; i = i + 1 {
|
||||
ctx._buffer[i] = 0
|
||||
}
|
||||
_blocks(ctx, ctx._buffer[:], true)
|
||||
}
|
||||
|
||||
// a += s
|
||||
field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &ctx._s) // _a unreduced
|
||||
field.fe_carry(&ctx._a, field.fe_relax_cast(&ctx._a)) // _a reduced
|
||||
|
||||
// return num_to_16_le_bytes(a)
|
||||
tmp: [32]byte = ---
|
||||
field.fe_to_bytes(&tmp, &ctx._a)
|
||||
copy_slice(dst, tmp[0:16])
|
||||
|
||||
reset(ctx)
|
||||
}
|
||||
|
||||
reset :: proc (ctx: ^Context) {
|
||||
mem.zero_explicit(&ctx._r, size_of(ctx._r))
|
||||
mem.zero_explicit(&ctx._a, size_of(ctx._a))
|
||||
mem.zero_explicit(&ctx._s, size_of(ctx._s))
|
||||
mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer))
|
||||
|
||||
ctx._is_initialized = false
|
||||
}
|
||||
|
||||
_blocks :: proc (ctx: ^Context, msg: []byte, final := false) {
|
||||
n: field.Tight_Field_Element = ---
|
||||
final_byte := byte(!final)
|
||||
|
||||
data := msg
|
||||
data_len := len(data)
|
||||
for data_len >= _BLOCK_SIZE {
|
||||
// n = le_bytes_to_num(msg[((i-1)*16)..*i*16] | [0x01])
|
||||
field.fe_from_bytes(&n, data[:_BLOCK_SIZE], final_byte, false)
|
||||
|
||||
// a += n
|
||||
field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &n) // _a unreduced
|
||||
|
||||
// a = (r * a) % p
|
||||
field.fe_carry_mul(&ctx._a, field.fe_relax_cast(&ctx._a), field.fe_relax_cast(&ctx._r)) // _a reduced
|
||||
|
||||
data = data[_BLOCK_SIZE:]
|
||||
data_len = data_len - _BLOCK_SIZE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package crypto
|
||||
|
||||
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows {
|
||||
_rand_bytes :: proc (dst: []byte) {
|
||||
unimplemented("crypto: rand_bytes not supported on this OS")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package crypto
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:sys/unix"
|
||||
|
||||
_MAX_PER_CALL_BYTES :: 33554431 // 2^25 - 1
|
||||
|
||||
_rand_bytes :: proc (dst: []byte) {
|
||||
dst := dst
|
||||
l := len(dst)
|
||||
|
||||
for l > 0 {
|
||||
to_read := min(l, _MAX_PER_CALL_BYTES)
|
||||
ret := unix.sys_getrandom(raw_data(dst), to_read, 0)
|
||||
if ret < 0 {
|
||||
switch os.Errno(-ret) {
|
||||
case os.EINTR:
|
||||
// Call interupted by a signal handler, just retry the
|
||||
// request.
|
||||
continue
|
||||
case os.ENOSYS:
|
||||
// The kernel is apparently prehistoric (< 3.17 circa 2014)
|
||||
// and does not support getrandom.
|
||||
panic("crypto: getrandom not available in kernel")
|
||||
case:
|
||||
// All other failures are things that should NEVER happen
|
||||
// unless the kernel interface changes (ie: the Linux
|
||||
// developers break userland).
|
||||
panic(fmt.tprintf("crypto: getrandom failed: %d", ret))
|
||||
}
|
||||
}
|
||||
|
||||
l -= ret
|
||||
dst = dst[ret:]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package crypto
|
||||
|
||||
import "core:c"
|
||||
|
||||
foreign import libc "system:c"
|
||||
foreign libc {
|
||||
arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) ---
|
||||
}
|
||||
|
||||
_rand_bytes :: proc (dst: []byte) {
|
||||
arc4random_buf(raw_data(dst), len(dst))
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package crypto
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:os"
|
||||
import "core:fmt"
|
||||
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
|
||||
if ret != os.ERROR_NONE {
|
||||
switch ret {
|
||||
case os.ERROR_INVALID_HANDLE:
|
||||
// The handle to the first parameter is invalid.
|
||||
// This should not happen here, since we explicitly pass nil to it
|
||||
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
|
||||
case os.ERROR_INVALID_PARAMETER:
|
||||
// One of the parameters was invalid
|
||||
panic("crypto: BCryptGenRandom Invalid parameter")
|
||||
case:
|
||||
// Unknown error
|
||||
panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,919 @@
|
||||
package ripemd
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation for the RIPEMD hashing algorithm as defined in <https://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_128 :: 16
|
||||
DIGEST_SIZE_160 :: 20
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_320 :: 40
|
||||
|
||||
// hash_string_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte {
|
||||
return hash_bytes_128(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: Ripemd128_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_128 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_128 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Ripemd128_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_128 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: Ripemd128_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_128 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_128(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_128(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_128]byte{}, false
|
||||
}
|
||||
|
||||
hash_128 :: proc {
|
||||
hash_stream_128,
|
||||
hash_file_128,
|
||||
hash_bytes_128,
|
||||
hash_string_128,
|
||||
hash_bytes_to_buffer_128,
|
||||
hash_string_to_buffer_128,
|
||||
}
|
||||
|
||||
// hash_string_160 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte {
|
||||
return hash_bytes_160(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_160 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
hash: [DIGEST_SIZE_160]byte
|
||||
ctx: Ripemd160_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_160 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_160 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Ripemd160_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_160 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) {
|
||||
hash: [DIGEST_SIZE_160]byte
|
||||
ctx: Ripemd160_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_160 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_160(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_160(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_160]byte{}, false
|
||||
}
|
||||
|
||||
hash_160 :: proc {
|
||||
hash_stream_160,
|
||||
hash_file_160,
|
||||
hash_bytes_160,
|
||||
hash_string_160,
|
||||
hash_bytes_to_buffer_160,
|
||||
hash_string_to_buffer_160,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Ripemd256_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Ripemd256_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Ripemd256_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_320 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_320 :: proc(data: string) -> [DIGEST_SIZE_320]byte {
|
||||
return hash_bytes_320(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_320 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_320 :: proc(data: []byte) -> [DIGEST_SIZE_320]byte {
|
||||
hash: [DIGEST_SIZE_320]byte
|
||||
ctx: Ripemd320_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_320 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_320 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_320(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_320 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_320 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_320, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Ripemd320_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_320 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_320 :: proc(s: io.Stream) -> ([DIGEST_SIZE_320]byte, bool) {
|
||||
hash: [DIGEST_SIZE_320]byte
|
||||
ctx: Ripemd320_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_320 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_320 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_320]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_320(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_320(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_320]byte{}, false
|
||||
}
|
||||
|
||||
hash_320 :: proc {
|
||||
hash_stream_320,
|
||||
hash_file_320,
|
||||
hash_bytes_320,
|
||||
hash_string_320,
|
||||
hash_bytes_to_buffer_320,
|
||||
hash_string_to_buffer_320,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^$T) {
|
||||
when T == Ripemd128_Context {
|
||||
ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3
|
||||
} else when T == Ripemd160_Context {
|
||||
ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4
|
||||
} else when T == Ripemd256_Context {
|
||||
ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3
|
||||
ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7] = S5, S6, S7, S8
|
||||
} else when T == Ripemd320_Context {
|
||||
ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4
|
||||
ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9] = S5, S6, S7, S8, S9
|
||||
}
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^$T, data: []byte) {
|
||||
ctx.tc += u64(len(data))
|
||||
data := data
|
||||
if ctx.nx > 0 {
|
||||
n := len(data)
|
||||
|
||||
when T == Ripemd128_Context {
|
||||
if n > RIPEMD_128_BLOCK_SIZE - ctx.nx {
|
||||
n = RIPEMD_128_BLOCK_SIZE - ctx.nx
|
||||
}
|
||||
} else when T == Ripemd160_Context {
|
||||
if n > RIPEMD_160_BLOCK_SIZE - ctx.nx {
|
||||
n = RIPEMD_160_BLOCK_SIZE - ctx.nx
|
||||
}
|
||||
} else when T == Ripemd256_Context{
|
||||
if n > RIPEMD_256_BLOCK_SIZE - ctx.nx {
|
||||
n = RIPEMD_256_BLOCK_SIZE - ctx.nx
|
||||
}
|
||||
} else when T == Ripemd320_Context{
|
||||
if n > RIPEMD_320_BLOCK_SIZE - ctx.nx {
|
||||
n = RIPEMD_320_BLOCK_SIZE - ctx.nx
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < n; i += 1 {
|
||||
ctx.x[ctx.nx + i] = data[i]
|
||||
}
|
||||
|
||||
ctx.nx += n
|
||||
when T == Ripemd128_Context {
|
||||
if ctx.nx == RIPEMD_128_BLOCK_SIZE {
|
||||
block(ctx, ctx.x[0:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
} else when T == Ripemd160_Context {
|
||||
if ctx.nx == RIPEMD_160_BLOCK_SIZE {
|
||||
block(ctx, ctx.x[0:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
} else when T == Ripemd256_Context{
|
||||
if ctx.nx == RIPEMD_256_BLOCK_SIZE {
|
||||
block(ctx, ctx.x[0:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
} else when T == Ripemd320_Context{
|
||||
if ctx.nx == RIPEMD_320_BLOCK_SIZE {
|
||||
block(ctx, ctx.x[0:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
n := block(ctx, data)
|
||||
data = data[n:]
|
||||
if len(data) > 0 {
|
||||
ctx.nx = copy(ctx.x[:], data)
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^$T, hash: []byte) {
|
||||
d := ctx
|
||||
tc := d.tc
|
||||
tmp: [64]byte
|
||||
tmp[0] = 0x80
|
||||
|
||||
if tc % 64 < 56 {
|
||||
update(d, tmp[0:56 - tc % 64])
|
||||
} else {
|
||||
update(d, tmp[0:64 + 56 - tc % 64])
|
||||
}
|
||||
|
||||
tc <<= 3
|
||||
for i : u32 = 0; i < 8; i += 1 {
|
||||
tmp[i] = byte(tc >> (8 * i))
|
||||
}
|
||||
|
||||
update(d, tmp[0:8])
|
||||
|
||||
when T == Ripemd128_Context {
|
||||
size :: RIPEMD_128_SIZE
|
||||
} else when T == Ripemd160_Context {
|
||||
size :: RIPEMD_160_SIZE
|
||||
} else when T == Ripemd256_Context{
|
||||
size :: RIPEMD_256_SIZE
|
||||
} else when T == Ripemd320_Context{
|
||||
size :: RIPEMD_320_SIZE
|
||||
}
|
||||
|
||||
digest: [size]byte
|
||||
for s, i in d.s {
|
||||
digest[i * 4] = byte(s)
|
||||
digest[i * 4 + 1] = byte(s >> 8)
|
||||
digest[i * 4 + 2] = byte(s >> 16)
|
||||
digest[i * 4 + 3] = byte(s >> 24)
|
||||
}
|
||||
copy(hash[:], digest[:])
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
RIPEMD implementation
|
||||
*/
|
||||
|
||||
Ripemd128_Context :: struct {
|
||||
s: [4]u32,
|
||||
x: [RIPEMD_128_BLOCK_SIZE]byte,
|
||||
nx: int,
|
||||
tc: u64,
|
||||
}
|
||||
|
||||
Ripemd160_Context :: struct {
|
||||
s: [5]u32,
|
||||
x: [RIPEMD_160_BLOCK_SIZE]byte,
|
||||
nx: int,
|
||||
tc: u64,
|
||||
}
|
||||
|
||||
Ripemd256_Context :: struct {
|
||||
s: [8]u32,
|
||||
x: [RIPEMD_256_BLOCK_SIZE]byte,
|
||||
nx: int,
|
||||
tc: u64,
|
||||
}
|
||||
|
||||
Ripemd320_Context :: struct {
|
||||
s: [10]u32,
|
||||
x: [RIPEMD_320_BLOCK_SIZE]byte,
|
||||
nx: int,
|
||||
tc: u64,
|
||||
}
|
||||
|
||||
RIPEMD_128_SIZE :: 16
|
||||
RIPEMD_128_BLOCK_SIZE :: 64
|
||||
RIPEMD_160_SIZE :: 20
|
||||
RIPEMD_160_BLOCK_SIZE :: 64
|
||||
RIPEMD_256_SIZE :: 32
|
||||
RIPEMD_256_BLOCK_SIZE :: 64
|
||||
RIPEMD_320_SIZE :: 40
|
||||
RIPEMD_320_BLOCK_SIZE :: 64
|
||||
|
||||
S0 :: 0x67452301
|
||||
S1 :: 0xefcdab89
|
||||
S2 :: 0x98badcfe
|
||||
S3 :: 0x10325476
|
||||
S4 :: 0xc3d2e1f0
|
||||
S5 :: 0x76543210
|
||||
S6 :: 0xfedcba98
|
||||
S7 :: 0x89abcdef
|
||||
S8 :: 0x01234567
|
||||
S9 :: 0x3c2d1e0f
|
||||
|
||||
RIPEMD_128_N0 := [64]uint {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
||||
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
|
||||
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
|
||||
}
|
||||
|
||||
RIPEMD_128_R0 := [64]uint {
|
||||
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
|
||||
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
|
||||
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
|
||||
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
|
||||
}
|
||||
|
||||
RIPEMD_128_N1 := [64]uint {
|
||||
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
|
||||
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
|
||||
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
|
||||
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
|
||||
}
|
||||
|
||||
RIPEMD_128_R1 := [64]uint {
|
||||
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
|
||||
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
|
||||
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
|
||||
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
|
||||
}
|
||||
|
||||
RIPEMD_160_N0 := [80]uint {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
||||
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
|
||||
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
|
||||
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
|
||||
}
|
||||
|
||||
RIPEMD_160_R0 := [80]uint {
|
||||
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
|
||||
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
|
||||
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
|
||||
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
|
||||
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
|
||||
}
|
||||
|
||||
RIPEMD_160_N1 := [80]uint {
|
||||
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
|
||||
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
|
||||
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
|
||||
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
|
||||
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
|
||||
}
|
||||
|
||||
RIPEMD_160_R1 := [80]uint {
|
||||
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
|
||||
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
|
||||
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
|
||||
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
|
||||
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
|
||||
}
|
||||
|
||||
block :: #force_inline proc (ctx: ^$T, p: []byte) -> int {
|
||||
when T == Ripemd128_Context {
|
||||
return ripemd_128_block(ctx, p)
|
||||
}
|
||||
else when T == Ripemd160_Context {
|
||||
return ripemd_160_block(ctx, p)
|
||||
}
|
||||
else when T == Ripemd256_Context {
|
||||
return ripemd_256_block(ctx, p)
|
||||
}
|
||||
else when T == Ripemd320_Context {
|
||||
return ripemd_320_block(ctx, p)
|
||||
}
|
||||
}
|
||||
|
||||
ripemd_128_block :: proc(ctx: ^$T, p: []byte) -> int {
|
||||
n := 0
|
||||
x: [16]u32 = ---
|
||||
alpha: u32 = ---
|
||||
p := p
|
||||
for len(p) >= RIPEMD_128_BLOCK_SIZE {
|
||||
a, b, c, d := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3]
|
||||
aa, bb, cc, dd := a, b, c, d
|
||||
for i,j := 0, 0; i < 16; i, j = i+1, j+4 {
|
||||
x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24
|
||||
}
|
||||
i := 0
|
||||
for i < 16 {
|
||||
alpha = a + (b ~ c ~ d) + x[RIPEMD_128_N0[i]]
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (bb & dd | cc &~ dd) + x[RIPEMD_128_N1[i]] + 0x50a28be6
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd= dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
for i < 32 {
|
||||
alpha = a + (d ~ (b & (c~d))) + x[RIPEMD_128_N0[i]] + 0x5a827999
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (dd ~ (bb | ~cc)) + x[RIPEMD_128_N1[i]] + 0x5c4dd124
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd = dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
for i < 48 {
|
||||
alpha = a + (d ~ (b | ~c)) + x[RIPEMD_128_N0[i]] + 0x6ed9eba1
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (dd ~ (bb & (cc~dd))) + x[RIPEMD_128_N1[i]] + 0x6d703ef3
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd = dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
for i < 64 {
|
||||
alpha = a + (c ~ (d & (b~c))) + x[RIPEMD_128_N0[i]] + 0x8f1bbcdc
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_128_N1[i]]
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd = dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
c = ctx.s[1] + c + dd
|
||||
ctx.s[1] = ctx.s[2] + d + aa
|
||||
ctx.s[2] = ctx.s[3] + a + bb
|
||||
ctx.s[3] = ctx.s[0] + b + cc
|
||||
ctx.s[0] = c
|
||||
p = p[RIPEMD_128_BLOCK_SIZE:]
|
||||
n += RIPEMD_128_BLOCK_SIZE
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
ripemd_160_block :: proc(ctx: ^$T, p: []byte) -> int {
|
||||
n := 0
|
||||
x: [16]u32 = ---
|
||||
alpha, beta: u32 = ---, ---
|
||||
p := p
|
||||
for len(p) >= RIPEMD_160_BLOCK_SIZE {
|
||||
a, b, c, d, e := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4]
|
||||
aa, bb, cc, dd, ee := a, b, c, d, e
|
||||
for i,j := 0, 0; i < 16; i, j = i+1, j+4 {
|
||||
x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24
|
||||
}
|
||||
i := 0
|
||||
for i < 16 {
|
||||
alpha = a + (b ~ c ~ d) + x[RIPEMD_160_N0[i]]
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb ~ (cc | ~dd)) + x[RIPEMD_160_N1[i]] + 0x50a28be6
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
for i < 32 {
|
||||
alpha = a + (b&c | ~b&d) + x[RIPEMD_160_N0[i]] + 0x5a827999
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb&dd | cc&~dd) + x[RIPEMD_160_N1[i]] + 0x5c4dd124
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
for i < 48 {
|
||||
alpha = a + (b | ~c ~ d) + x[RIPEMD_160_N0[i]] + 0x6ed9eba1
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb | ~cc ~ dd) + x[RIPEMD_160_N1[i]] + 0x6d703ef3
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
for i < 64 {
|
||||
alpha = a + (b&d | c&~d) + x[RIPEMD_160_N0[i]] + 0x8f1bbcdc
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb&cc | ~bb&dd) + x[RIPEMD_160_N1[i]] + 0x7a6d76e9
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
for i < 80 {
|
||||
alpha = a + (b ~ (c | ~d)) + x[RIPEMD_160_N0[i]] + 0xa953fd4e
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_160_N1[i]]
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
dd += c + ctx.s[1]
|
||||
ctx.s[1] = ctx.s[2] + d + ee
|
||||
ctx.s[2] = ctx.s[3] + e + aa
|
||||
ctx.s[3] = ctx.s[4] + a + bb
|
||||
ctx.s[4] = ctx.s[0] + b + cc
|
||||
ctx.s[0] = dd
|
||||
p = p[RIPEMD_160_BLOCK_SIZE:]
|
||||
n += RIPEMD_160_BLOCK_SIZE
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
ripemd_256_block :: proc(ctx: ^$T, p: []byte) -> int {
|
||||
n := 0
|
||||
x: [16]u32 = ---
|
||||
alpha: u32 = ---
|
||||
p := p
|
||||
for len(p) >= RIPEMD_256_BLOCK_SIZE {
|
||||
a, b, c, d := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3]
|
||||
aa, bb, cc, dd := ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7]
|
||||
for i,j := 0, 0; i < 16; i, j = i+1, j+4 {
|
||||
x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24
|
||||
}
|
||||
i := 0
|
||||
for i < 16 {
|
||||
alpha = a + (b ~ c ~ d) + x[RIPEMD_128_N0[i]]
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (bb & dd | cc &~ dd) + x[RIPEMD_128_N1[i]] + 0x50a28be6
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd= dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
t := a
|
||||
a = aa
|
||||
aa = t
|
||||
for i < 32 {
|
||||
alpha = a + (d ~ (b & (c~d))) + x[RIPEMD_128_N0[i]] + 0x5a827999
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (dd ~ (bb | ~cc)) + x[RIPEMD_128_N1[i]] + 0x5c4dd124
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd = dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
t = b
|
||||
b = bb
|
||||
bb = t
|
||||
for i < 48 {
|
||||
alpha = a + (d ~ (b | ~c)) + x[RIPEMD_128_N0[i]] + 0x6ed9eba1
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (dd ~ (bb & (cc~dd))) + x[RIPEMD_128_N1[i]] + 0x6d703ef3
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd = dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
t = c
|
||||
c = cc
|
||||
cc = t
|
||||
for i < 64 {
|
||||
alpha = a + (c ~ (d & (b~c))) + x[RIPEMD_128_N0[i]] + 0x8f1bbcdc
|
||||
s := int(RIPEMD_128_R0[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
a, b, c, d = d, alpha, b, c
|
||||
alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_128_N1[i]]
|
||||
s = int(RIPEMD_128_R1[i])
|
||||
alpha = util.ROTL32(alpha, s)
|
||||
aa, bb, cc, dd = dd, alpha, bb, cc
|
||||
i += 1
|
||||
}
|
||||
t = d
|
||||
d = dd
|
||||
dd = t
|
||||
ctx.s[0] += a
|
||||
ctx.s[1] += b
|
||||
ctx.s[2] += c
|
||||
ctx.s[3] += d
|
||||
ctx.s[4] += aa
|
||||
ctx.s[5] += bb
|
||||
ctx.s[6] += cc
|
||||
ctx.s[7] += dd
|
||||
p = p[RIPEMD_256_BLOCK_SIZE:]
|
||||
n += RIPEMD_256_BLOCK_SIZE
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
ripemd_320_block :: proc(ctx: ^$T, p: []byte) -> int {
|
||||
n := 0
|
||||
x: [16]u32 = ---
|
||||
alpha, beta: u32 = ---, ---
|
||||
p := p
|
||||
for len(p) >= RIPEMD_320_BLOCK_SIZE {
|
||||
a, b, c, d, e := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4]
|
||||
aa, bb, cc, dd, ee := ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9]
|
||||
for i,j := 0, 0; i < 16; i, j = i+1, j+4 {
|
||||
x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24
|
||||
}
|
||||
i := 0
|
||||
for i < 16 {
|
||||
alpha = a + (b ~ c ~ d) + x[RIPEMD_160_N0[i]]
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb ~ (cc | ~dd)) + x[RIPEMD_160_N1[i]] + 0x50a28be6
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
t := b
|
||||
b = bb
|
||||
bb = t
|
||||
for i < 32 {
|
||||
alpha = a + (b&c | ~b&d) + x[RIPEMD_160_N0[i]] + 0x5a827999
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb&dd | cc&~dd) + x[RIPEMD_160_N1[i]] + 0x5c4dd124
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
t = d
|
||||
d = dd
|
||||
dd = t
|
||||
for i < 48 {
|
||||
alpha = a + (b | ~c ~ d) + x[RIPEMD_160_N0[i]] + 0x6ed9eba1
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb | ~cc ~ dd) + x[RIPEMD_160_N1[i]] + 0x6d703ef3
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
t = a
|
||||
a = aa
|
||||
aa = t
|
||||
for i < 64 {
|
||||
alpha = a + (b&d | c&~d) + x[RIPEMD_160_N0[i]] + 0x8f1bbcdc
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb&cc | ~bb&dd) + x[RIPEMD_160_N1[i]] + 0x7a6d76e9
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
t = c
|
||||
c = cc
|
||||
cc = t
|
||||
for i < 80 {
|
||||
alpha = a + (b ~ (c | ~d)) + x[RIPEMD_160_N0[i]] + 0xa953fd4e
|
||||
s := int(RIPEMD_160_R0[i])
|
||||
alpha = util.ROTL32(alpha, s) + e
|
||||
beta = util.ROTL32(c, 10)
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_160_N1[i]]
|
||||
s = int(RIPEMD_160_R1[i])
|
||||
alpha = util.ROTL32(alpha, s) + ee
|
||||
beta = util.ROTL32(cc, 10)
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
i += 1
|
||||
}
|
||||
t = e
|
||||
e = ee
|
||||
ee = t
|
||||
ctx.s[0] += a
|
||||
ctx.s[1] += b
|
||||
ctx.s[2] += c
|
||||
ctx.s[3] += d
|
||||
ctx.s[4] += e
|
||||
ctx.s[5] += aa
|
||||
ctx.s[6] += bb
|
||||
ctx.s[7] += cc
|
||||
ctx.s[8] += dd
|
||||
ctx.s[9] += ee
|
||||
p = p[RIPEMD_320_BLOCK_SIZE:]
|
||||
n += RIPEMD_320_BLOCK_SIZE
|
||||
}
|
||||
return n
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
package sha1
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the SHA1 hashing algorithm, as defined in RFC 3174 <https://datatracker.ietf.org/doc/html/rfc3174>
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 20
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Sha1_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Sha1_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Sha1_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Sha1_Context) {
|
||||
ctx.state[0] = 0x67452301
|
||||
ctx.state[1] = 0xefcdab89
|
||||
ctx.state[2] = 0x98badcfe
|
||||
ctx.state[3] = 0x10325476
|
||||
ctx.state[4] = 0xc3d2e1f0
|
||||
ctx.k[0] = 0x5a827999
|
||||
ctx.k[1] = 0x6ed9eba1
|
||||
ctx.k[2] = 0x8f1bbcdc
|
||||
ctx.k[3] = 0xca62c1d6
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Sha1_Context, data: []byte) {
|
||||
for i := 0; i < len(data); i += 1 {
|
||||
ctx.data[ctx.datalen] = data[i]
|
||||
ctx.datalen += 1
|
||||
if (ctx.datalen == BLOCK_SIZE) {
|
||||
transform(ctx, ctx.data[:])
|
||||
ctx.bitlen += 512
|
||||
ctx.datalen = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Sha1_Context, hash: []byte) {
|
||||
i := ctx.datalen
|
||||
|
||||
if ctx.datalen < 56 {
|
||||
ctx.data[i] = 0x80
|
||||
i += 1
|
||||
for i < 56 {
|
||||
ctx.data[i] = 0x00
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctx.data[i] = 0x80
|
||||
i += 1
|
||||
for i < BLOCK_SIZE {
|
||||
ctx.data[i] = 0x00
|
||||
i += 1
|
||||
}
|
||||
transform(ctx, ctx.data[:])
|
||||
mem.set(&ctx.data, 0, 56)
|
||||
}
|
||||
|
||||
ctx.bitlen += u64(ctx.datalen * 8)
|
||||
ctx.data[63] = u8(ctx.bitlen)
|
||||
ctx.data[62] = u8(ctx.bitlen >> 8)
|
||||
ctx.data[61] = u8(ctx.bitlen >> 16)
|
||||
ctx.data[60] = u8(ctx.bitlen >> 24)
|
||||
ctx.data[59] = u8(ctx.bitlen >> 32)
|
||||
ctx.data[58] = u8(ctx.bitlen >> 40)
|
||||
ctx.data[57] = u8(ctx.bitlen >> 48)
|
||||
ctx.data[56] = u8(ctx.bitlen >> 56)
|
||||
transform(ctx, ctx.data[:])
|
||||
|
||||
for j: u32 = 0; j < 4; j += 1 {
|
||||
hash[j] = u8(ctx.state[0] >> (24 - j * 8)) & 0x000000ff
|
||||
hash[j + 4] = u8(ctx.state[1] >> (24 - j * 8)) & 0x000000ff
|
||||
hash[j + 8] = u8(ctx.state[2] >> (24 - j * 8)) & 0x000000ff
|
||||
hash[j + 12] = u8(ctx.state[3] >> (24 - j * 8)) & 0x000000ff
|
||||
hash[j + 16] = u8(ctx.state[4] >> (24 - j * 8)) & 0x000000ff
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SHA1 implementation
|
||||
*/
|
||||
|
||||
BLOCK_SIZE :: 64
|
||||
|
||||
Sha1_Context :: struct {
|
||||
data: [BLOCK_SIZE]byte,
|
||||
datalen: u32,
|
||||
bitlen: u64,
|
||||
state: [5]u32,
|
||||
k: [4]u32,
|
||||
}
|
||||
|
||||
transform :: proc(ctx: ^Sha1_Context, data: []byte) {
|
||||
a, b, c, d, e, i, j, t: u32
|
||||
m: [80]u32
|
||||
|
||||
for i, j = 0, 0; i < 16; i += 1 {
|
||||
m[i] = u32(data[j]) << 24 + u32(data[j + 1]) << 16 + u32(data[j + 2]) << 8 + u32(data[j + 3])
|
||||
j += 4
|
||||
}
|
||||
for i < 80 {
|
||||
m[i] = (m[i - 3] ~ m[i - 8] ~ m[i - 14] ~ m[i - 16])
|
||||
m[i] = (m[i] << 1) | (m[i] >> 31)
|
||||
i += 1
|
||||
}
|
||||
|
||||
a = ctx.state[0]
|
||||
b = ctx.state[1]
|
||||
c = ctx.state[2]
|
||||
d = ctx.state[3]
|
||||
e = ctx.state[4]
|
||||
|
||||
for i = 0; i < 20; i += 1 {
|
||||
t = util.ROTL32(a, 5) + ((b & c) ~ (~b & d)) + e + ctx.k[0] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = util.ROTL32(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
}
|
||||
for i < 40 {
|
||||
t = util.ROTL32(a, 5) + (b ~ c ~ d) + e + ctx.k[1] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = util.ROTL32(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
i += 1
|
||||
}
|
||||
for i < 60 {
|
||||
t = util.ROTL32(a, 5) + ((b & c) ~ (b & d) ~ (c & d)) + e + ctx.k[2] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = util.ROTL32(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
i += 1
|
||||
}
|
||||
for i < 80 {
|
||||
t = util.ROTL32(a, 5) + (b ~ c ~ d) + e + ctx.k[3] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = util.ROTL32(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
i += 1
|
||||
}
|
||||
|
||||
ctx.state[0] += a
|
||||
ctx.state[1] += b
|
||||
ctx.state[2] += c
|
||||
ctx.state[3] += d
|
||||
ctx.state[4] += e
|
||||
}
|
||||
@@ -0,0 +1,684 @@
|
||||
package sha2
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the SHA2 hashing algorithm, as defined in <https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf>
|
||||
and in RFC 3874 <https://datatracker.ietf.org/doc/html/rfc3874>
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_224 :: 28
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_384 :: 48
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
|
||||
return hash_bytes_224(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Sha256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_224 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Sha256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_224 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_224 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_224(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_224(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_224]byte{}, false
|
||||
}
|
||||
|
||||
hash_224 :: proc {
|
||||
hash_stream_224,
|
||||
hash_file_224,
|
||||
hash_bytes_224,
|
||||
hash_string_224,
|
||||
hash_bytes_to_buffer_224,
|
||||
hash_string_to_buffer_224,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Sha256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Sha256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
|
||||
return hash_bytes_384(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_384 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_384 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_384 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_384(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_384(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_384]byte{}, false
|
||||
}
|
||||
|
||||
hash_384 :: proc {
|
||||
hash_stream_384,
|
||||
hash_file_384,
|
||||
hash_bytes_384,
|
||||
hash_string_384,
|
||||
hash_bytes_to_buffer_384,
|
||||
hash_string_to_buffer_384,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Sha512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^$T) {
|
||||
when T == Sha256_Context {
|
||||
if ctx.is224 {
|
||||
ctx.h[0] = 0xc1059ed8
|
||||
ctx.h[1] = 0x367cd507
|
||||
ctx.h[2] = 0x3070dd17
|
||||
ctx.h[3] = 0xf70e5939
|
||||
ctx.h[4] = 0xffc00b31
|
||||
ctx.h[5] = 0x68581511
|
||||
ctx.h[6] = 0x64f98fa7
|
||||
ctx.h[7] = 0xbefa4fa4
|
||||
} else {
|
||||
ctx.h[0] = 0x6a09e667
|
||||
ctx.h[1] = 0xbb67ae85
|
||||
ctx.h[2] = 0x3c6ef372
|
||||
ctx.h[3] = 0xa54ff53a
|
||||
ctx.h[4] = 0x510e527f
|
||||
ctx.h[5] = 0x9b05688c
|
||||
ctx.h[6] = 0x1f83d9ab
|
||||
ctx.h[7] = 0x5be0cd19
|
||||
}
|
||||
} else when T == Sha512_Context {
|
||||
if ctx.is384 {
|
||||
ctx.h[0] = 0xcbbb9d5dc1059ed8
|
||||
ctx.h[1] = 0x629a292a367cd507
|
||||
ctx.h[2] = 0x9159015a3070dd17
|
||||
ctx.h[3] = 0x152fecd8f70e5939
|
||||
ctx.h[4] = 0x67332667ffc00b31
|
||||
ctx.h[5] = 0x8eb44a8768581511
|
||||
ctx.h[6] = 0xdb0c2e0d64f98fa7
|
||||
ctx.h[7] = 0x47b5481dbefa4fa4
|
||||
} else {
|
||||
ctx.h[0] = 0x6a09e667f3bcc908
|
||||
ctx.h[1] = 0xbb67ae8584caa73b
|
||||
ctx.h[2] = 0x3c6ef372fe94f82b
|
||||
ctx.h[3] = 0xa54ff53a5f1d36f1
|
||||
ctx.h[4] = 0x510e527fade682d1
|
||||
ctx.h[5] = 0x9b05688c2b3e6c1f
|
||||
ctx.h[6] = 0x1f83d9abfb41bd6b
|
||||
ctx.h[7] = 0x5be0cd19137e2179
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^$T, data: []byte) {
|
||||
length := uint(len(data))
|
||||
block_nb: uint
|
||||
new_len, rem_len, tmp_len: uint
|
||||
shifted_message := make([]byte, length)
|
||||
|
||||
when T == Sha256_Context {
|
||||
CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE
|
||||
} else when T == Sha512_Context {
|
||||
CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE
|
||||
}
|
||||
|
||||
tmp_len = CURR_BLOCK_SIZE - ctx.length
|
||||
rem_len = length < tmp_len ? length : tmp_len
|
||||
copy(ctx.block[ctx.length:], data[:rem_len])
|
||||
|
||||
if ctx.length + length < CURR_BLOCK_SIZE {
|
||||
ctx.length += length
|
||||
return
|
||||
}
|
||||
|
||||
new_len = length - rem_len
|
||||
block_nb = new_len / CURR_BLOCK_SIZE
|
||||
shifted_message = data[rem_len:]
|
||||
|
||||
sha2_transf(ctx, ctx.block[:], 1)
|
||||
sha2_transf(ctx, shifted_message, block_nb)
|
||||
|
||||
rem_len = new_len % CURR_BLOCK_SIZE
|
||||
if rem_len > 0 {
|
||||
when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])}
|
||||
else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])}
|
||||
}
|
||||
|
||||
ctx.length = rem_len
|
||||
when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6}
|
||||
else when T == Sha512_Context {ctx.tot_len += (block_nb + 1) << 7}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^$T, hash: []byte) {
|
||||
block_nb, pm_len, len_b: u32
|
||||
i: i32
|
||||
|
||||
when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE}
|
||||
else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE}
|
||||
|
||||
when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)}
|
||||
else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)}
|
||||
|
||||
len_b = u32(ctx.tot_len + ctx.length) << 3
|
||||
when T == Sha256_Context {pm_len = block_nb << 6}
|
||||
else when T == Sha512_Context {pm_len = block_nb << 7}
|
||||
|
||||
mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length))
|
||||
ctx.block[ctx.length] = 0x80
|
||||
|
||||
util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b)
|
||||
|
||||
sha2_transf(ctx, ctx.block[:], uint(block_nb))
|
||||
|
||||
when T == Sha256_Context {
|
||||
if ctx.is224 {
|
||||
for i = 0; i < 7; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])}
|
||||
} else {
|
||||
for i = 0; i < 8; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])}
|
||||
}
|
||||
} else when T == Sha512_Context {
|
||||
if ctx.is384 {
|
||||
for i = 0; i < 6; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])}
|
||||
} else {
|
||||
for i = 0; i < 8; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SHA2 implementation
|
||||
*/
|
||||
|
||||
SHA256_BLOCK_SIZE :: 64
|
||||
SHA512_BLOCK_SIZE :: 128
|
||||
|
||||
Sha256_Context :: struct {
|
||||
tot_len: uint,
|
||||
length: uint,
|
||||
block: [128]byte,
|
||||
h: [8]u32,
|
||||
is224: bool,
|
||||
}
|
||||
|
||||
Sha512_Context :: struct {
|
||||
tot_len: uint,
|
||||
length: uint,
|
||||
block: [256]byte,
|
||||
h: [8]u64,
|
||||
is384: bool,
|
||||
}
|
||||
|
||||
sha256_k := [64]u32 {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
||||
}
|
||||
|
||||
sha512_k := [80]u64 {
|
||||
0x428a2f98d728ae22, 0x7137449123ef65cd,
|
||||
0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
|
||||
0x3956c25bf348b538, 0x59f111f1b605d019,
|
||||
0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
|
||||
0xd807aa98a3030242, 0x12835b0145706fbe,
|
||||
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
|
||||
0x72be5d74f27b896f, 0x80deb1fe3b1696b1,
|
||||
0x9bdc06a725c71235, 0xc19bf174cf692694,
|
||||
0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
|
||||
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275, 0x4a7484aa6ea6e483,
|
||||
0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
|
||||
0x983e5152ee66dfab, 0xa831c66d2db43210,
|
||||
0xb00327c898fb213f, 0xbf597fc7beef0ee4,
|
||||
0xc6e00bf33da88fc2, 0xd5a79147930aa725,
|
||||
0x06ca6351e003826f, 0x142929670a0e6e70,
|
||||
0x27b70a8546d22ffc, 0x2e1b21385c26c926,
|
||||
0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
|
||||
0x650a73548baf63de, 0x766a0abb3c77b2a8,
|
||||
0x81c2c92e47edaee6, 0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364, 0xa81a664bbc423001,
|
||||
0xc24b8b70d0f89791, 0xc76c51a30654be30,
|
||||
0xd192e819d6ef5218, 0xd69906245565a910,
|
||||
0xf40e35855771202a, 0x106aa07032bbd1b8,
|
||||
0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
|
||||
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
|
||||
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
|
||||
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
|
||||
0x748f82ee5defb2fc, 0x78a5636f43172f60,
|
||||
0x84c87814a1f0ab72, 0x8cc702081a6439ec,
|
||||
0x90befffa23631e28, 0xa4506cebde82bde9,
|
||||
0xbef9a3f7b2c67915, 0xc67178f2e372532b,
|
||||
0xca273eceea26619c, 0xd186b8c721c0c207,
|
||||
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
|
||||
0x06f067aa72176fba, 0x0a637dc5a2c898a6,
|
||||
0x113f9804bef90dae, 0x1b710b35131c471b,
|
||||
0x28db77f523047d84, 0x32caab7b40c72493,
|
||||
0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
|
||||
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
|
||||
0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
|
||||
}
|
||||
|
||||
SHA256_CH :: #force_inline proc "contextless"(x, y, z: u32) -> u32 {
|
||||
return (x & y) ~ (~x & z)
|
||||
}
|
||||
|
||||
SHA256_MAJ :: #force_inline proc "contextless"(x, y, z: u32) -> u32 {
|
||||
return (x & y) ~ (x & z) ~ (y & z)
|
||||
}
|
||||
|
||||
SHA512_CH :: #force_inline proc "contextless"(x, y, z: u64) -> u64 {
|
||||
return (x & y) ~ (~x & z)
|
||||
}
|
||||
|
||||
SHA512_MAJ :: #force_inline proc "contextless"(x, y, z: u64) -> u64 {
|
||||
return (x & y) ~ (x & z) ~ (y & z)
|
||||
}
|
||||
|
||||
SHA256_F1 :: #force_inline proc "contextless"(x: u32) -> u32 {
|
||||
return util.ROTR32(x, 2) ~ util.ROTR32(x, 13) ~ util.ROTR32(x, 22)
|
||||
}
|
||||
|
||||
SHA256_F2 :: #force_inline proc "contextless"(x: u32) -> u32 {
|
||||
return util.ROTR32(x, 6) ~ util.ROTR32(x, 11) ~ util.ROTR32(x, 25)
|
||||
}
|
||||
|
||||
SHA256_F3 :: #force_inline proc "contextless"(x: u32) -> u32 {
|
||||
return util.ROTR32(x, 7) ~ util.ROTR32(x, 18) ~ (x >> 3)
|
||||
}
|
||||
|
||||
SHA256_F4 :: #force_inline proc "contextless"(x: u32) -> u32 {
|
||||
return util.ROTR32(x, 17) ~ util.ROTR32(x, 19) ~ (x >> 10)
|
||||
}
|
||||
|
||||
SHA512_F1 :: #force_inline proc "contextless"(x: u64) -> u64 {
|
||||
return util.ROTR64(x, 28) ~ util.ROTR64(x, 34) ~ util.ROTR64(x, 39)
|
||||
}
|
||||
|
||||
SHA512_F2 :: #force_inline proc "contextless"(x: u64) -> u64 {
|
||||
return util.ROTR64(x, 14) ~ util.ROTR64(x, 18) ~ util.ROTR64(x, 41)
|
||||
}
|
||||
|
||||
SHA512_F3 :: #force_inline proc "contextless"(x: u64) -> u64 {
|
||||
return util.ROTR64(x, 1) ~ util.ROTR64(x, 8) ~ (x >> 7)
|
||||
}
|
||||
|
||||
SHA512_F4 :: #force_inline proc "contextless"(x: u64) -> u64 {
|
||||
return util.ROTR64(x, 19) ~ util.ROTR64(x, 61) ~ (x >> 6)
|
||||
}
|
||||
|
||||
PACK32 :: #force_inline proc "contextless"(b: []byte, x: ^u32) {
|
||||
x^ = u32(b[3]) | u32(b[2]) << 8 | u32(b[1]) << 16 | u32(b[0]) << 24
|
||||
}
|
||||
|
||||
PACK64 :: #force_inline proc "contextless"(b: []byte, x: ^u64) {
|
||||
x^ = u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56
|
||||
}
|
||||
|
||||
sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) {
|
||||
when T == Sha256_Context {
|
||||
w: [64]u32
|
||||
wv: [8]u32
|
||||
t1, t2: u32
|
||||
} else when T == Sha512_Context {
|
||||
w: [80]u64
|
||||
wv: [8]u64
|
||||
t1, t2: u64
|
||||
}
|
||||
|
||||
sub_block := make([]byte, len(data))
|
||||
i, j: i32
|
||||
|
||||
for i = 0; i < i32(block_nb); i += 1 {
|
||||
when T == Sha256_Context {
|
||||
sub_block = data[i << 6:]
|
||||
} else when T == Sha512_Context {
|
||||
sub_block = data[i << 7:]
|
||||
}
|
||||
|
||||
for j = 0; j < 16; j += 1 {
|
||||
when T == Sha256_Context {
|
||||
PACK32(sub_block[j << 2:], &w[j])
|
||||
} else when T == Sha512_Context {
|
||||
PACK64(sub_block[j << 3:], &w[j])
|
||||
}
|
||||
}
|
||||
|
||||
when T == Sha256_Context {
|
||||
for j = 16; j < 64; j += 1 {
|
||||
w[j] = SHA256_F4(w[j - 2]) + w[j - 7] + SHA256_F3(w[j - 15]) + w[j - 16]
|
||||
}
|
||||
} else when T == Sha512_Context {
|
||||
for j = 16; j < 80; j += 1 {
|
||||
w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16]
|
||||
}
|
||||
}
|
||||
|
||||
for j = 0; j < 8; j += 1 {
|
||||
wv[j] = ctx.h[j]
|
||||
}
|
||||
|
||||
when T == Sha256_Context {
|
||||
for j = 0; j < 64; j += 1 {
|
||||
t1 = wv[7] + SHA256_F2(wv[4]) + SHA256_CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]
|
||||
t2 = SHA256_F1(wv[0]) + SHA256_MAJ(wv[0], wv[1], wv[2])
|
||||
wv[7] = wv[6]
|
||||
wv[6] = wv[5]
|
||||
wv[5] = wv[4]
|
||||
wv[4] = wv[3] + t1
|
||||
wv[3] = wv[2]
|
||||
wv[2] = wv[1]
|
||||
wv[1] = wv[0]
|
||||
wv[0] = t1 + t2
|
||||
}
|
||||
} else when T == Sha512_Context {
|
||||
for j = 0; j < 80; j += 1 {
|
||||
t1 = wv[7] + SHA512_F2(wv[4]) + SHA512_CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j]
|
||||
t2 = SHA512_F1(wv[0]) + SHA512_MAJ(wv[0], wv[1], wv[2])
|
||||
wv[7] = wv[6]
|
||||
wv[6] = wv[5]
|
||||
wv[5] = wv[4]
|
||||
wv[4] = wv[3] + t1
|
||||
wv[3] = wv[2]
|
||||
wv[2] = wv[1]
|
||||
wv[1] = wv[0]
|
||||
wv[0] = t1 + t2
|
||||
}
|
||||
}
|
||||
|
||||
for j = 0; j < 8; j += 1 {
|
||||
ctx.h[j] += wv[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
package sha3
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the SHA3 hashing algorithm. The SHAKE functionality can be found in package shake.
|
||||
If you wish to compute a Keccak hash, you can use the keccak package, it will use the original padding.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../_sha3"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_224 :: 28
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_384 :: 48
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
|
||||
return hash_bytes_224(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_224 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_224 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_224 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_224(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_224(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_224]byte{}, false
|
||||
}
|
||||
|
||||
hash_224 :: proc {
|
||||
hash_stream_224,
|
||||
hash_file_224,
|
||||
hash_bytes_224,
|
||||
hash_string_224,
|
||||
hash_bytes_to_buffer_224,
|
||||
hash_string_to_buffer_224,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
|
||||
return hash_bytes_384(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_384 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_384 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_384 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_384(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_384(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_384]byte{}, false
|
||||
}
|
||||
|
||||
hash_384 :: proc {
|
||||
hash_stream_384,
|
||||
hash_file_384,
|
||||
hash_bytes_384,
|
||||
hash_string_384,
|
||||
hash_bytes_to_buffer_384,
|
||||
hash_string_to_buffer_384,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Sha3_Context :: _sha3.Sha3_Context
|
||||
|
||||
init :: proc(ctx: ^_sha3.Sha3_Context) {
|
||||
_sha3.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
|
||||
_sha3.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
|
||||
_sha3.final(ctx, hash)
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
package shake
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the SHAKE hashing algorithm.
|
||||
The SHA3 functionality can be found in package sha3.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../_sha3"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_128 :: 16
|
||||
DIGEST_SIZE_256 :: 32
|
||||
|
||||
// hash_string_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte {
|
||||
return hash_bytes_128(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_128
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.shake_xof(&ctx)
|
||||
_sha3.shake_out(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_128 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_128 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_128
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.shake_xof(&ctx)
|
||||
_sha3.shake_out(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_128 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_128
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.shake_xof(&ctx)
|
||||
_sha3.shake_out(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_128 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_128(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_128(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_128]byte{}, false
|
||||
}
|
||||
|
||||
hash_128 :: proc {
|
||||
hash_stream_128,
|
||||
hash_file_128,
|
||||
hash_bytes_128,
|
||||
hash_string_128,
|
||||
hash_bytes_to_buffer_128,
|
||||
hash_string_to_buffer_128,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.shake_xof(&ctx)
|
||||
_sha3.shake_out(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
_sha3.init(&ctx)
|
||||
_sha3.update(&ctx, data)
|
||||
_sha3.shake_xof(&ctx)
|
||||
_sha3.shake_out(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: _sha3.Sha3_Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
_sha3.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_sha3.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_sha3.shake_xof(&ctx)
|
||||
_sha3.shake_out(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Shake_Context :: _sha3.Sha3_Context
|
||||
|
||||
init :: proc(ctx: ^_sha3.Sha3_Context) {
|
||||
_sha3.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
|
||||
_sha3.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
|
||||
_sha3.shake_xof(ctx)
|
||||
_sha3.shake_out(ctx, hash[:])
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
package siphash
|
||||
|
||||
/*
|
||||
Copyright 2022 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog: Initial implementation.
|
||||
|
||||
Implementation of the SipHash hashing algorithm, as defined at <https://github.com/veorq/SipHash> and <https://www.aumasson.jp/siphash/siphash.pdf>
|
||||
|
||||
Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
|
||||
*/
|
||||
|
||||
import "core:crypto"
|
||||
import "core:crypto/util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
KEY_SIZE :: 16
|
||||
DIGEST_SIZE :: 8
|
||||
|
||||
// sum_string_1_3 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_string_1_3 :: proc(msg, key: string) -> u64 {
|
||||
return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key))
|
||||
}
|
||||
|
||||
// sum_bytes_1_3 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 {
|
||||
ctx: Context
|
||||
hash: u64
|
||||
init(&ctx, key, 1, 3)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, &hash)
|
||||
return hash
|
||||
}
|
||||
|
||||
// sum_string_to_buffer_1_3 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) {
|
||||
sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||
}
|
||||
|
||||
// sum_bytes_to_buffer_1_3 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) {
|
||||
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||
hash := sum_bytes_1_3(msg, key)
|
||||
_collect_output(dst[:], hash)
|
||||
}
|
||||
|
||||
sum_1_3 :: proc {
|
||||
sum_string_1_3,
|
||||
sum_bytes_1_3,
|
||||
sum_string_to_buffer_1_3,
|
||||
sum_bytes_to_buffer_1_3,
|
||||
}
|
||||
|
||||
// verify_u64_1_3 will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||
return sum_bytes_1_3(msg, key) == tag
|
||||
}
|
||||
|
||||
// verify_bytes will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool {
|
||||
derived_tag: [8]byte
|
||||
sum_bytes_to_buffer_1_3(msg, key, derived_tag[:])
|
||||
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||
}
|
||||
|
||||
verify_1_3 :: proc {
|
||||
verify_bytes_1_3,
|
||||
verify_u64_1_3,
|
||||
}
|
||||
|
||||
// sum_string_2_4 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_string_2_4 :: proc(msg, key: string) -> u64 {
|
||||
return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key))
|
||||
}
|
||||
|
||||
// sum_bytes_2_4 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 {
|
||||
ctx: Context
|
||||
hash: u64
|
||||
init(&ctx, key, 2, 4)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, &hash)
|
||||
return hash
|
||||
}
|
||||
|
||||
// sum_string_to_buffer_2_4 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) {
|
||||
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||
}
|
||||
|
||||
// sum_bytes_to_buffer_2_4 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) {
|
||||
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||
hash := sum_bytes_2_4(msg, key)
|
||||
_collect_output(dst[:], hash)
|
||||
}
|
||||
|
||||
sum_2_4 :: proc {
|
||||
sum_string_2_4,
|
||||
sum_bytes_2_4,
|
||||
sum_string_to_buffer_2_4,
|
||||
sum_bytes_to_buffer_2_4,
|
||||
}
|
||||
|
||||
sum_string :: sum_string_2_4
|
||||
sum_bytes :: sum_bytes_2_4
|
||||
sum_string_to_buffer :: sum_string_to_buffer_2_4
|
||||
sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4
|
||||
sum :: proc {
|
||||
sum_string,
|
||||
sum_bytes,
|
||||
sum_string_to_buffer,
|
||||
sum_bytes_to_buffer,
|
||||
}
|
||||
|
||||
// verify_u64_2_4 will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||
return sum_bytes_2_4(msg, key) == tag
|
||||
}
|
||||
|
||||
// verify_bytes will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool {
|
||||
derived_tag: [8]byte
|
||||
sum_bytes_to_buffer_2_4(msg, key, derived_tag[:])
|
||||
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||
}
|
||||
|
||||
verify_2_4 :: proc {
|
||||
verify_bytes_2_4,
|
||||
verify_u64_2_4,
|
||||
}
|
||||
|
||||
verify_bytes :: verify_bytes_2_4
|
||||
verify_u64 :: verify_u64_2_4
|
||||
verify :: proc {
|
||||
verify_bytes,
|
||||
verify_u64,
|
||||
}
|
||||
|
||||
// sum_string_4_8 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_string_4_8 :: proc(msg, key: string) -> u64 {
|
||||
return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key))
|
||||
}
|
||||
|
||||
// sum_bytes_4_8 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 {
|
||||
ctx: Context
|
||||
hash: u64
|
||||
init(&ctx, key, 4, 8)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, &hash)
|
||||
return hash
|
||||
}
|
||||
|
||||
// sum_string_to_buffer_4_8 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) {
|
||||
sum_bytes_to_buffer_4_8(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||
}
|
||||
|
||||
// sum_bytes_to_buffer_4_8 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) {
|
||||
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||
hash := sum_bytes_4_8(msg, key)
|
||||
_collect_output(dst[:], hash)
|
||||
}
|
||||
|
||||
sum_4_8 :: proc {
|
||||
sum_string_4_8,
|
||||
sum_bytes_4_8,
|
||||
sum_string_to_buffer_4_8,
|
||||
sum_bytes_to_buffer_4_8,
|
||||
}
|
||||
|
||||
// verify_u64_4_8 will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||
return sum_bytes_4_8(msg, key) == tag
|
||||
}
|
||||
|
||||
// verify_bytes will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool {
|
||||
derived_tag: [8]byte
|
||||
sum_bytes_to_buffer_4_8(msg, key, derived_tag[:])
|
||||
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||
}
|
||||
|
||||
verify_4_8 :: proc {
|
||||
verify_bytes_4_8,
|
||||
verify_u64_4_8,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
|
||||
assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16")
|
||||
ctx.c_rounds = c_rounds
|
||||
ctx.d_rounds = d_rounds
|
||||
is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) ||
|
||||
(ctx.c_rounds == 2 && ctx.d_rounds == 4) ||
|
||||
(ctx.c_rounds == 4 && ctx.d_rounds == 8)
|
||||
assert(is_valid_setting, "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)")
|
||||
ctx.k0 = util.U64_LE(key[:8])
|
||||
ctx.k1 = util.U64_LE(key[8:])
|
||||
ctx.v0 = 0x736f6d6570736575 ~ ctx.k0
|
||||
ctx.v1 = 0x646f72616e646f6d ~ ctx.k1
|
||||
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
||||
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
assert(ctx.is_initialized, "crypto/siphash: Context is not initalized")
|
||||
ctx.last_block = len(data) / 8 * 8
|
||||
ctx.buf = data
|
||||
i := 0
|
||||
m: u64
|
||||
for i < ctx.last_block {
|
||||
m = u64(ctx.buf[i] & 0xff)
|
||||
i += 1
|
||||
|
||||
for r in u64(1)..<8 {
|
||||
m |= u64(ctx.buf[i] & 0xff) << (r * 8)
|
||||
i += 1
|
||||
}
|
||||
|
||||
ctx.v3 ~= m
|
||||
for _ in 0..<ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Context, dst: ^u64) {
|
||||
m: u64
|
||||
for i := len(ctx.buf) - 1; i >= ctx.last_block; i -= 1 {
|
||||
m <<= 8
|
||||
m |= u64(ctx.buf[i] & 0xff)
|
||||
}
|
||||
m |= u64(len(ctx.buf) << 56)
|
||||
|
||||
ctx.v3 ~= m
|
||||
|
||||
for _ in 0..<ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
ctx.v2 ~= 0xff
|
||||
|
||||
for _ in 0..<ctx.d_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
dst^ = ctx.v0 ~ ctx.v1 ~ ctx.v2 ~ ctx.v3
|
||||
|
||||
reset(ctx)
|
||||
}
|
||||
|
||||
reset :: proc(ctx: ^Context) {
|
||||
ctx.k0, ctx.k1 = 0, 0
|
||||
ctx.v0, ctx.v1 = 0, 0
|
||||
ctx.v2, ctx.v3 = 0, 0
|
||||
ctx.last_block = 0
|
||||
ctx.c_rounds = 0
|
||||
ctx.d_rounds = 0
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
Context :: struct {
|
||||
v0, v1, v2, v3: u64, // State values
|
||||
k0, k1: u64, // Split key
|
||||
c_rounds: int, // Number of message rounds
|
||||
d_rounds: int, // Number of finalization rounds
|
||||
buf: []byte, // Provided data
|
||||
last_block: int, // Offset from the last block
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
||||
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
||||
}
|
||||
|
||||
_collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) {
|
||||
dst[0] = _get_byte(7, hash)
|
||||
dst[1] = _get_byte(6, hash)
|
||||
dst[2] = _get_byte(5, hash)
|
||||
dst[3] = _get_byte(4, hash)
|
||||
dst[4] = _get_byte(3, hash)
|
||||
dst[5] = _get_byte(2, hash)
|
||||
dst[6] = _get_byte(1, hash)
|
||||
dst[7] = _get_byte(0, hash)
|
||||
}
|
||||
|
||||
_compress :: #force_inline proc "contextless" (ctx: ^Context) {
|
||||
ctx.v0 += ctx.v1
|
||||
ctx.v1 = util.ROTL64(ctx.v1, 13)
|
||||
ctx.v1 ~= ctx.v0
|
||||
ctx.v0 = util.ROTL64(ctx.v0, 32)
|
||||
ctx.v2 += ctx.v3
|
||||
ctx.v3 = util.ROTL64(ctx.v3, 16)
|
||||
ctx.v3 ~= ctx.v2
|
||||
ctx.v0 += ctx.v3
|
||||
ctx.v3 = util.ROTL64(ctx.v3, 21)
|
||||
ctx.v3 ~= ctx.v0
|
||||
ctx.v2 += ctx.v1
|
||||
ctx.v1 = util.ROTL64(ctx.v1, 17)
|
||||
ctx.v1 ~= ctx.v2
|
||||
ctx.v2 = util.ROTL64(ctx.v2, 32)
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package sm3
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the SM3 hashing algorithm, as defined in <https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 32
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Sm3_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Sm3_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Sm3_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Sm3_Context) {
|
||||
ctx.state[0] = IV[0]
|
||||
ctx.state[1] = IV[1]
|
||||
ctx.state[2] = IV[2]
|
||||
ctx.state[3] = IV[3]
|
||||
ctx.state[4] = IV[4]
|
||||
ctx.state[5] = IV[5]
|
||||
ctx.state[6] = IV[6]
|
||||
ctx.state[7] = IV[7]
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Sm3_Context, data: []byte) {
|
||||
data := data
|
||||
ctx.length += u64(len(data))
|
||||
|
||||
if ctx.bitlength > 0 {
|
||||
n := copy(ctx.x[ctx.bitlength:], data[:])
|
||||
ctx.bitlength += u64(n)
|
||||
if ctx.bitlength == 64 {
|
||||
block(ctx, ctx.x[:])
|
||||
ctx.bitlength = 0
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= 64 {
|
||||
n := len(data) &~ (64 - 1)
|
||||
block(ctx, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) > 0 {
|
||||
ctx.bitlength = u64(copy(ctx.x[:], data[:]))
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Sm3_Context, hash: []byte) {
|
||||
length := ctx.length
|
||||
|
||||
pad: [64]byte
|
||||
pad[0] = 0x80
|
||||
if length % 64 < 56 {
|
||||
update(ctx, pad[0: 56 - length % 64])
|
||||
} else {
|
||||
update(ctx, pad[0: 64 + 56 - length % 64])
|
||||
}
|
||||
|
||||
length <<= 3
|
||||
util.PUT_U64_BE(pad[:], length)
|
||||
update(ctx, pad[0: 8])
|
||||
assert(ctx.bitlength == 0)
|
||||
|
||||
util.PUT_U32_BE(hash[0:], ctx.state[0])
|
||||
util.PUT_U32_BE(hash[4:], ctx.state[1])
|
||||
util.PUT_U32_BE(hash[8:], ctx.state[2])
|
||||
util.PUT_U32_BE(hash[12:], ctx.state[3])
|
||||
util.PUT_U32_BE(hash[16:], ctx.state[4])
|
||||
util.PUT_U32_BE(hash[20:], ctx.state[5])
|
||||
util.PUT_U32_BE(hash[24:], ctx.state[6])
|
||||
util.PUT_U32_BE(hash[28:], ctx.state[7])
|
||||
}
|
||||
|
||||
/*
|
||||
SM3 implementation
|
||||
*/
|
||||
|
||||
Sm3_Context :: struct {
|
||||
state: [8]u32,
|
||||
x: [64]byte,
|
||||
bitlength: u64,
|
||||
length: u64,
|
||||
}
|
||||
|
||||
IV := [8]u32 {
|
||||
0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600,
|
||||
0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e,
|
||||
}
|
||||
|
||||
block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) {
|
||||
buf := buf
|
||||
|
||||
w: [68]u32
|
||||
wp: [64]u32
|
||||
|
||||
state0, state1, state2, state3 := ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3]
|
||||
state4, state5, state6, state7 := ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7]
|
||||
|
||||
for len(buf) >= 64 {
|
||||
for i := 0; i < 16; i += 1 {
|
||||
j := i * 4
|
||||
w[i] = u32(buf[j]) << 24 | u32(buf[j + 1]) << 16 | u32(buf[j + 2]) << 8 | u32(buf[j + 3])
|
||||
}
|
||||
for i := 16; i < 68; i += 1 {
|
||||
p1v := w[i - 16] ~ w[i - 9] ~ util.ROTL32(w[i - 3], 15)
|
||||
// @note(zh): inlined P1
|
||||
w[i] = p1v ~ util.ROTL32(p1v, 15) ~ util.ROTL32(p1v, 23) ~ util.ROTL32(w[i - 13], 7) ~ w[i - 6]
|
||||
}
|
||||
for i := 0; i < 64; i += 1 {
|
||||
wp[i] = w[i] ~ w[i + 4]
|
||||
}
|
||||
|
||||
a, b, c, d := state0, state1, state2, state3
|
||||
e, f, g, h := state4, state5, state6, state7
|
||||
|
||||
for i := 0; i < 16; i += 1 {
|
||||
v1 := util.ROTL32(u32(a), 12)
|
||||
ss1 := util.ROTL32(v1 + u32(e) + util.ROTL32(0x79cc4519, i), 7)
|
||||
ss2 := ss1 ~ v1
|
||||
|
||||
// @note(zh): inlined FF1
|
||||
tt1 := u32(a ~ b ~ c) + u32(d) + ss2 + wp[i]
|
||||
// @note(zh): inlined GG1
|
||||
tt2 := u32(e ~ f ~ g) + u32(h) + ss1 + w[i]
|
||||
|
||||
a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c
|
||||
// @note(zh): inlined P0
|
||||
e, f, g, h = (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g
|
||||
}
|
||||
|
||||
for i := 16; i < 64; i += 1 {
|
||||
v := util.ROTL32(u32(a), 12)
|
||||
ss1 := util.ROTL32(v + u32(e) + util.ROTL32(0x7a879d8a, i % 32), 7)
|
||||
ss2 := ss1 ~ v
|
||||
|
||||
// @note(zh): inlined FF2
|
||||
tt1 := u32(((a & b) | (a & c) | (b & c)) + d) + ss2 + wp[i]
|
||||
// @note(zh): inlined GG2
|
||||
tt2 := u32(((e & f) | ((~e) & g)) + h) + ss1 + w[i]
|
||||
|
||||
a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c
|
||||
// @note(zh): inlined P0
|
||||
e, f, g, h = (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g
|
||||
}
|
||||
|
||||
state0 ~= a
|
||||
state1 ~= b
|
||||
state2 ~= c
|
||||
state3 ~= d
|
||||
state4 ~= e
|
||||
state5 ~= f
|
||||
state6 ~= g
|
||||
state7 ~= h
|
||||
|
||||
buf = buf[64:]
|
||||
}
|
||||
|
||||
ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] = state0, state1, state2, state3
|
||||
ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] = state4, state5, state6, state7
|
||||
}
|
||||
@@ -0,0 +1,517 @@
|
||||
package streebog
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the Streebog hashing algorithm, standardized as GOST R 34.11-2012 in RFC 6986 <https://datatracker.ietf.org/doc/html/rfc6986>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Streebog_Context
|
||||
ctx.is256 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Streebog_Context
|
||||
ctx.is256 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Streebog_Context
|
||||
ctx.is256 = true
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Streebog_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Streebog_Context
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Streebog_Context
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Streebog_Context) {
|
||||
if ctx.is256 {
|
||||
ctx.hash_size = 256
|
||||
for _, i in ctx.h {
|
||||
ctx.h[i] = 0x01
|
||||
}
|
||||
} else {
|
||||
ctx.hash_size = 512
|
||||
}
|
||||
ctx.v_512[1] = 0x02
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Streebog_Context, data: []byte) {
|
||||
length := u64(len(data))
|
||||
chk_size: u64
|
||||
data := data
|
||||
for (length > 63) && (ctx.buf_size == 0) {
|
||||
stage2(ctx, data)
|
||||
data = data[64:]
|
||||
length -= 64
|
||||
}
|
||||
|
||||
for length != 0 {
|
||||
chk_size = 64 - ctx.buf_size
|
||||
if chk_size > length {
|
||||
chk_size = length
|
||||
}
|
||||
copy(ctx.buffer[ctx.buf_size:], data[:chk_size])
|
||||
ctx.buf_size += chk_size
|
||||
length -= chk_size
|
||||
data = data[chk_size:]
|
||||
if ctx.buf_size == 64 {
|
||||
stage2(ctx, ctx.buffer[:])
|
||||
ctx.buf_size = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Streebog_Context, hash: []byte) {
|
||||
t: [64]byte
|
||||
t[1] = byte((ctx.buf_size * 8) >> 8) & 0xff
|
||||
t[0] = byte((ctx.buf_size) * 8) & 0xff
|
||||
|
||||
padding(ctx)
|
||||
|
||||
G(ctx.h[:], ctx.n[:], ctx.buffer[:])
|
||||
|
||||
add_mod_512(ctx.n[:], t[:], ctx.n[:])
|
||||
add_mod_512(ctx.sigma[:], ctx.buffer[:], ctx.sigma[:])
|
||||
|
||||
G(ctx.h[:], ctx.v_0[:], ctx.n[:])
|
||||
G(ctx.h[:], ctx.v_0[:], ctx.sigma[:])
|
||||
|
||||
if ctx.is256 {
|
||||
copy(hash[:], ctx.h[32:])
|
||||
} else {
|
||||
copy(hash[:], ctx.h[:])
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Streebog implementation
|
||||
*/
|
||||
|
||||
PI := [256]byte {
|
||||
252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4, 77,
|
||||
233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205, 95, 193,
|
||||
249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1, 142, 79,
|
||||
5, 132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127, 212, 211, 31,
|
||||
235, 52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 204,
|
||||
181, 112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71, 156, 183, 93, 135,
|
||||
21, 161, 150, 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158, 178, 177,
|
||||
50, 117, 25, 61, 255, 53, 138, 126, 109, 84, 198, 128, 195, 189, 13, 87,
|
||||
223, 245, 36, 169, 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185, 3,
|
||||
224, 15, 236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 78, 51, 10, 74,
|
||||
167, 151, 96, 115, 30, 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65,
|
||||
173, 69, 70, 146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 149, 59,
|
||||
7, 88, 179, 64, 134, 172, 29, 247, 48, 55, 107, 228, 136, 217, 231, 137,
|
||||
225, 27, 131, 73, 76, 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97,
|
||||
32, 113, 103, 164, 45, 43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82,
|
||||
89, 166, 116, 210, 230, 244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182,
|
||||
}
|
||||
|
||||
TAU := [64]byte {
|
||||
0, 8, 16, 24, 32, 40, 48, 56,
|
||||
1, 9, 17, 25, 33, 41, 49, 57,
|
||||
2, 10, 18, 26, 34, 42, 50, 58,
|
||||
3, 11, 19, 27, 35, 43, 51, 59,
|
||||
4, 12, 20, 28, 36, 44, 52, 60,
|
||||
5, 13, 21, 29, 37, 45, 53, 61,
|
||||
6, 14, 22, 30, 38, 46, 54, 62,
|
||||
7, 15, 23, 31, 39, 47, 55, 63,
|
||||
}
|
||||
|
||||
STREEBOG_A := [64]u64 {
|
||||
0x8e20faa72ba0b470, 0x47107ddd9b505a38, 0xad08b0e0c3282d1c, 0xd8045870ef14980e,
|
||||
0x6c022c38f90a4c07, 0x3601161cf205268d, 0x1b8e0b0e798c13c8, 0x83478b07b2468764,
|
||||
0xa011d380818e8f40, 0x5086e740ce47c920, 0x2843fd2067adea10, 0x14aff010bdd87508,
|
||||
0x0ad97808d06cb404, 0x05e23c0468365a02, 0x8c711e02341b2d01, 0x46b60f011a83988e,
|
||||
0x90dab52a387ae76f, 0x486dd4151c3dfdb9, 0x24b86a840e90f0d2, 0x125c354207487869,
|
||||
0x092e94218d243cba, 0x8a174a9ec8121e5d, 0x4585254f64090fa0, 0xaccc9ca9328a8950,
|
||||
0x9d4df05d5f661451, 0xc0a878a0a1330aa6, 0x60543c50de970553, 0x302a1e286fc58ca7,
|
||||
0x18150f14b9ec46dd, 0x0c84890ad27623e0, 0x0642ca05693b9f70, 0x0321658cba93c138,
|
||||
0x86275df09ce8aaa8, 0x439da0784e745554, 0xafc0503c273aa42a, 0xd960281e9d1d5215,
|
||||
0xe230140fc0802984, 0x71180a8960409a42, 0xb60c05ca30204d21, 0x5b068c651810a89e,
|
||||
0x456c34887a3805b9, 0xac361a443d1c8cd2, 0x561b0d22900e4669, 0x2b838811480723ba,
|
||||
0x9bcf4486248d9f5d, 0xc3e9224312c8c1a0, 0xeffa11af0964ee50, 0xf97d86d98a327728,
|
||||
0xe4fa2054a80b329c, 0x727d102a548b194e, 0x39b008152acb8227, 0x9258048415eb419d,
|
||||
0x492c024284fbaec0, 0xaa16012142f35760, 0x550b8e9e21f7a530, 0xa48b474f9ef5dc18,
|
||||
0x70a6a56e2440598e, 0x3853dc371220a247, 0x1ca76e95091051ad, 0x0edd37c48a08a6d8,
|
||||
0x07e095624504536c, 0x8d70c431ac02a736, 0xc83862965601dd1b, 0x641c314b2b8ee083,
|
||||
}
|
||||
|
||||
STREEBOG_C := [12][64]byte {
|
||||
{
|
||||
0x07, 0x45, 0xa6, 0xf2, 0x59, 0x65, 0x80, 0xdd,
|
||||
0x23, 0x4d, 0x74, 0xcc, 0x36, 0x74, 0x76, 0x05,
|
||||
0x15, 0xd3, 0x60, 0xa4, 0x08, 0x2a, 0x42, 0xa2,
|
||||
0x01, 0x69, 0x67, 0x92, 0x91, 0xe0, 0x7c, 0x4b,
|
||||
0xfc, 0xc4, 0x85, 0x75, 0x8d, 0xb8, 0x4e, 0x71,
|
||||
0x16, 0xd0, 0x45, 0x2e, 0x43, 0x76, 0x6a, 0x2f,
|
||||
0x1f, 0x7c, 0x65, 0xc0, 0x81, 0x2f, 0xcb, 0xeb,
|
||||
0xe9, 0xda, 0xca, 0x1e, 0xda, 0x5b, 0x08, 0xb1,
|
||||
},
|
||||
{
|
||||
0xb7, 0x9b, 0xb1, 0x21, 0x70, 0x04, 0x79, 0xe6,
|
||||
0x56, 0xcd, 0xcb, 0xd7, 0x1b, 0xa2, 0xdd, 0x55,
|
||||
0xca, 0xa7, 0x0a, 0xdb, 0xc2, 0x61, 0xb5, 0x5c,
|
||||
0x58, 0x99, 0xd6, 0x12, 0x6b, 0x17, 0xb5, 0x9a,
|
||||
0x31, 0x01, 0xb5, 0x16, 0x0f, 0x5e, 0xd5, 0x61,
|
||||
0x98, 0x2b, 0x23, 0x0a, 0x72, 0xea, 0xfe, 0xf3,
|
||||
0xd7, 0xb5, 0x70, 0x0f, 0x46, 0x9d, 0xe3, 0x4f,
|
||||
0x1a, 0x2f, 0x9d, 0xa9, 0x8a, 0xb5, 0xa3, 0x6f,
|
||||
},
|
||||
{
|
||||
0xb2, 0x0a, 0xba, 0x0a, 0xf5, 0x96, 0x1e, 0x99,
|
||||
0x31, 0xdb, 0x7a, 0x86, 0x43, 0xf4, 0xb6, 0xc2,
|
||||
0x09, 0xdb, 0x62, 0x60, 0x37, 0x3a, 0xc9, 0xc1,
|
||||
0xb1, 0x9e, 0x35, 0x90, 0xe4, 0x0f, 0xe2, 0xd3,
|
||||
0x7b, 0x7b, 0x29, 0xb1, 0x14, 0x75, 0xea, 0xf2,
|
||||
0x8b, 0x1f, 0x9c, 0x52, 0x5f, 0x5e, 0xf1, 0x06,
|
||||
0x35, 0x84, 0x3d, 0x6a, 0x28, 0xfc, 0x39, 0x0a,
|
||||
0xc7, 0x2f, 0xce, 0x2b, 0xac, 0xdc, 0x74, 0xf5,
|
||||
},
|
||||
{
|
||||
0x2e, 0xd1, 0xe3, 0x84, 0xbc, 0xbe, 0x0c, 0x22,
|
||||
0xf1, 0x37, 0xe8, 0x93, 0xa1, 0xea, 0x53, 0x34,
|
||||
0xbe, 0x03, 0x52, 0x93, 0x33, 0x13, 0xb7, 0xd8,
|
||||
0x75, 0xd6, 0x03, 0xed, 0x82, 0x2c, 0xd7, 0xa9,
|
||||
0x3f, 0x35, 0x5e, 0x68, 0xad, 0x1c, 0x72, 0x9d,
|
||||
0x7d, 0x3c, 0x5c, 0x33, 0x7e, 0x85, 0x8e, 0x48,
|
||||
0xdd, 0xe4, 0x71, 0x5d, 0xa0, 0xe1, 0x48, 0xf9,
|
||||
0xd2, 0x66, 0x15, 0xe8, 0xb3, 0xdf, 0x1f, 0xef,
|
||||
},
|
||||
{
|
||||
0x57, 0xfe, 0x6c, 0x7c, 0xfd, 0x58, 0x17, 0x60,
|
||||
0xf5, 0x63, 0xea, 0xa9, 0x7e, 0xa2, 0x56, 0x7a,
|
||||
0x16, 0x1a, 0x27, 0x23, 0xb7, 0x00, 0xff, 0xdf,
|
||||
0xa3, 0xf5, 0x3a, 0x25, 0x47, 0x17, 0xcd, 0xbf,
|
||||
0xbd, 0xff, 0x0f, 0x80, 0xd7, 0x35, 0x9e, 0x35,
|
||||
0x4a, 0x10, 0x86, 0x16, 0x1f, 0x1c, 0x15, 0x7f,
|
||||
0x63, 0x23, 0xa9, 0x6c, 0x0c, 0x41, 0x3f, 0x9a,
|
||||
0x99, 0x47, 0x47, 0xad, 0xac, 0x6b, 0xea, 0x4b,
|
||||
},
|
||||
{
|
||||
0x6e, 0x7d, 0x64, 0x46, 0x7a, 0x40, 0x68, 0xfa,
|
||||
0x35, 0x4f, 0x90, 0x36, 0x72, 0xc5, 0x71, 0xbf,
|
||||
0xb6, 0xc6, 0xbe, 0xc2, 0x66, 0x1f, 0xf2, 0x0a,
|
||||
0xb4, 0xb7, 0x9a, 0x1c, 0xb7, 0xa6, 0xfa, 0xcf,
|
||||
0xc6, 0x8e, 0xf0, 0x9a, 0xb4, 0x9a, 0x7f, 0x18,
|
||||
0x6c, 0xa4, 0x42, 0x51, 0xf9, 0xc4, 0x66, 0x2d,
|
||||
0xc0, 0x39, 0x30, 0x7a, 0x3b, 0xc3, 0xa4, 0x6f,
|
||||
0xd9, 0xd3, 0x3a, 0x1d, 0xae, 0xae, 0x4f, 0xae,
|
||||
},
|
||||
{
|
||||
0x93, 0xd4, 0x14, 0x3a, 0x4d, 0x56, 0x86, 0x88,
|
||||
0xf3, 0x4a, 0x3c, 0xa2, 0x4c, 0x45, 0x17, 0x35,
|
||||
0x04, 0x05, 0x4a, 0x28, 0x83, 0x69, 0x47, 0x06,
|
||||
0x37, 0x2c, 0x82, 0x2d, 0xc5, 0xab, 0x92, 0x09,
|
||||
0xc9, 0x93, 0x7a, 0x19, 0x33, 0x3e, 0x47, 0xd3,
|
||||
0xc9, 0x87, 0xbf, 0xe6, 0xc7, 0xc6, 0x9e, 0x39,
|
||||
0x54, 0x09, 0x24, 0xbf, 0xfe, 0x86, 0xac, 0x51,
|
||||
0xec, 0xc5, 0xaa, 0xee, 0x16, 0x0e, 0xc7, 0xf4,
|
||||
},
|
||||
{
|
||||
0x1e, 0xe7, 0x02, 0xbf, 0xd4, 0x0d, 0x7f, 0xa4,
|
||||
0xd9, 0xa8, 0x51, 0x59, 0x35, 0xc2, 0xac, 0x36,
|
||||
0x2f, 0xc4, 0xa5, 0xd1, 0x2b, 0x8d, 0xd1, 0x69,
|
||||
0x90, 0x06, 0x9b, 0x92, 0xcb, 0x2b, 0x89, 0xf4,
|
||||
0x9a, 0xc4, 0xdb, 0x4d, 0x3b, 0x44, 0xb4, 0x89,
|
||||
0x1e, 0xde, 0x36, 0x9c, 0x71, 0xf8, 0xb7, 0x4e,
|
||||
0x41, 0x41, 0x6e, 0x0c, 0x02, 0xaa, 0xe7, 0x03,
|
||||
0xa7, 0xc9, 0x93, 0x4d, 0x42, 0x5b, 0x1f, 0x9b,
|
||||
},
|
||||
{
|
||||
0xdb, 0x5a, 0x23, 0x83, 0x51, 0x44, 0x61, 0x72,
|
||||
0x60, 0x2a, 0x1f, 0xcb, 0x92, 0xdc, 0x38, 0x0e,
|
||||
0x54, 0x9c, 0x07, 0xa6, 0x9a, 0x8a, 0x2b, 0x7b,
|
||||
0xb1, 0xce, 0xb2, 0xdb, 0x0b, 0x44, 0x0a, 0x80,
|
||||
0x84, 0x09, 0x0d, 0xe0, 0xb7, 0x55, 0xd9, 0x3c,
|
||||
0x24, 0x42, 0x89, 0x25, 0x1b, 0x3a, 0x7d, 0x3a,
|
||||
0xde, 0x5f, 0x16, 0xec, 0xd8, 0x9a, 0x4c, 0x94,
|
||||
0x9b, 0x22, 0x31, 0x16, 0x54, 0x5a, 0x8f, 0x37,
|
||||
},
|
||||
{
|
||||
0xed, 0x9c, 0x45, 0x98, 0xfb, 0xc7, 0xb4, 0x74,
|
||||
0xc3, 0xb6, 0x3b, 0x15, 0xd1, 0xfa, 0x98, 0x36,
|
||||
0xf4, 0x52, 0x76, 0x3b, 0x30, 0x6c, 0x1e, 0x7a,
|
||||
0x4b, 0x33, 0x69, 0xaf, 0x02, 0x67, 0xe7, 0x9f,
|
||||
0x03, 0x61, 0x33, 0x1b, 0x8a, 0xe1, 0xff, 0x1f,
|
||||
0xdb, 0x78, 0x8a, 0xff, 0x1c, 0xe7, 0x41, 0x89,
|
||||
0xf3, 0xf3, 0xe4, 0xb2, 0x48, 0xe5, 0x2a, 0x38,
|
||||
0x52, 0x6f, 0x05, 0x80, 0xa6, 0xde, 0xbe, 0xab,
|
||||
},
|
||||
{
|
||||
0x1b, 0x2d, 0xf3, 0x81, 0xcd, 0xa4, 0xca, 0x6b,
|
||||
0x5d, 0xd8, 0x6f, 0xc0, 0x4a, 0x59, 0xa2, 0xde,
|
||||
0x98, 0x6e, 0x47, 0x7d, 0x1d, 0xcd, 0xba, 0xef,
|
||||
0xca, 0xb9, 0x48, 0xea, 0xef, 0x71, 0x1d, 0x8a,
|
||||
0x79, 0x66, 0x84, 0x14, 0x21, 0x80, 0x01, 0x20,
|
||||
0x61, 0x07, 0xab, 0xeb, 0xbb, 0x6b, 0xfa, 0xd8,
|
||||
0x94, 0xfe, 0x5a, 0x63, 0xcd, 0xc6, 0x02, 0x30,
|
||||
0xfb, 0x89, 0xc8, 0xef, 0xd0, 0x9e, 0xcd, 0x7b,
|
||||
},
|
||||
{
|
||||
0x20, 0xd7, 0x1b, 0xf1, 0x4a, 0x92, 0xbc, 0x48,
|
||||
0x99, 0x1b, 0xb2, 0xd9, 0xd5, 0x17, 0xf4, 0xfa,
|
||||
0x52, 0x28, 0xe1, 0x88, 0xaa, 0xa4, 0x1d, 0xe7,
|
||||
0x86, 0xcc, 0x91, 0x18, 0x9d, 0xef, 0x80, 0x5d,
|
||||
0x9b, 0x9f, 0x21, 0x30, 0xd4, 0x12, 0x20, 0xf8,
|
||||
0x77, 0x1d, 0xdf, 0xbc, 0x32, 0x3c, 0xa4, 0xcd,
|
||||
0x7a, 0xb1, 0x49, 0x04, 0xb0, 0x80, 0x13, 0xd2,
|
||||
0xba, 0x31, 0x16, 0xf1, 0x67, 0xe7, 0x8e, 0x37,
|
||||
},
|
||||
}
|
||||
|
||||
Streebog_Context :: struct {
|
||||
buffer: [64]byte,
|
||||
h: [64]byte,
|
||||
n: [64]byte,
|
||||
sigma: [64]byte,
|
||||
v_0: [64]byte,
|
||||
v_512: [64]byte,
|
||||
buf_size: u64,
|
||||
hash_size: int,
|
||||
is256: bool,
|
||||
}
|
||||
|
||||
add_mod_512 :: proc(first_vector, second_vector, result_vector: []byte) {
|
||||
t: i32 = 0
|
||||
for i: i32 = 0; i < 64; i += 1 {
|
||||
t = i32(first_vector[i]) + i32(second_vector[i]) + (t >> 8)
|
||||
result_vector[i] = byte(t & 0xff)
|
||||
}
|
||||
}
|
||||
|
||||
X :: #force_inline proc(a, k, out: []byte) {
|
||||
for i := 0; i < 64; i += 1 {
|
||||
out[i] = a[i] ~ k[i]
|
||||
}
|
||||
}
|
||||
|
||||
S :: #force_inline proc(state: []byte) {
|
||||
t: [64]byte
|
||||
for i: i32 = 63; i >= 0; i -= 1 {
|
||||
t[i] = PI[state[i]]
|
||||
}
|
||||
copy(state, t[:])
|
||||
}
|
||||
|
||||
P :: #force_inline proc(state: []byte) {
|
||||
t: [64]byte
|
||||
for i: i32 = 63; i >= 0; i -= 1 {
|
||||
t[i] = state[TAU[i]]
|
||||
}
|
||||
copy(state, t[:])
|
||||
}
|
||||
|
||||
L :: #force_inline proc(state: []byte) {
|
||||
ins := util.cast_slice([]u64, state)
|
||||
out: [8]u64
|
||||
for i: i32 = 7; i >= 0; i -= 1 {
|
||||
for j: i32 = 63; j >= 0; j -= 1 {
|
||||
if (ins[i] >> u32(j)) & 1 != 0 {
|
||||
out[i] ~= STREEBOG_A[63 - j]
|
||||
}
|
||||
}
|
||||
}
|
||||
copy(state, util.cast_slice([]byte, out[:]))
|
||||
}
|
||||
|
||||
E :: #force_inline proc(K, m, state: []byte) {
|
||||
X(m, K, state)
|
||||
for i: i32 = 0; i < 12; i += 1 {
|
||||
S(state)
|
||||
P(state)
|
||||
L(state)
|
||||
get_key(K, i)
|
||||
X(state, K, state)
|
||||
}
|
||||
}
|
||||
|
||||
get_key :: #force_inline proc(K: []byte, i: i32) {
|
||||
X(K, STREEBOG_C[i][:], K)
|
||||
S(K)
|
||||
P(K)
|
||||
L(K)
|
||||
}
|
||||
|
||||
G :: #force_inline proc(h, N, m: []byte) {
|
||||
t, K: [64]byte
|
||||
X(N, h, K[:])
|
||||
S(K[:])
|
||||
P(K[:])
|
||||
L(K[:])
|
||||
E(K[:], m, t[:])
|
||||
X(t[:], h, t[:])
|
||||
X(t[:], m, h)
|
||||
}
|
||||
|
||||
stage2 :: proc(ctx: ^Streebog_Context, m: []byte) {
|
||||
G(ctx.h[:], ctx.n[:], m)
|
||||
add_mod_512(ctx.n[:], ctx.v_512[:], ctx.n[:])
|
||||
add_mod_512(ctx.sigma[:], m, ctx.sigma[:])
|
||||
}
|
||||
|
||||
padding :: proc(ctx: ^Streebog_Context) {
|
||||
if ctx.buf_size < 64 {
|
||||
t: [64]byte
|
||||
copy(t[:], ctx.buffer[:int(ctx.buf_size)])
|
||||
t[ctx.buf_size] = 0x01
|
||||
copy(ctx.buffer[:], t[:])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
package tiger
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the Tiger1 variant of the Tiger hashing algorithm as defined in <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../_tiger"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_128 :: 16
|
||||
DIGEST_SIZE_160 :: 20
|
||||
DIGEST_SIZE_192 :: 24
|
||||
|
||||
// hash_string_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte {
|
||||
return hash_bytes_128(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_128 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_128 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_128 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_tiger.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_128 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_128(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_128(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_128]byte{}, false
|
||||
}
|
||||
|
||||
hash_128 :: proc {
|
||||
hash_stream_128,
|
||||
hash_file_128,
|
||||
hash_bytes_128,
|
||||
hash_string_128,
|
||||
hash_bytes_to_buffer_128,
|
||||
hash_string_to_buffer_128,
|
||||
}
|
||||
|
||||
// hash_string_160 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte {
|
||||
return hash_bytes_160(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_160 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
hash: [DIGEST_SIZE_160]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_160 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_160 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_160 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) {
|
||||
hash: [DIGEST_SIZE_160]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_tiger.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_160 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_160(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_160(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_160]byte{}, false
|
||||
}
|
||||
|
||||
hash_160 :: proc {
|
||||
hash_stream_160,
|
||||
hash_file_160,
|
||||
hash_bytes_160,
|
||||
hash_string_160,
|
||||
hash_bytes_to_buffer_160,
|
||||
hash_string_to_buffer_160,
|
||||
}
|
||||
|
||||
// hash_string_192 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte {
|
||||
return hash_bytes_192(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_192 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
||||
hash: [DIGEST_SIZE_192]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_192 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_192 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_192 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_192 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) {
|
||||
hash: [DIGEST_SIZE_192]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 1
|
||||
_tiger.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_tiger.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_192 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_192(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_192(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_192]byte{}, false
|
||||
}
|
||||
|
||||
hash_192 :: proc {
|
||||
hash_stream_192,
|
||||
hash_file_192,
|
||||
hash_bytes_192,
|
||||
hash_string_192,
|
||||
hash_bytes_to_buffer_192,
|
||||
hash_string_to_buffer_192,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Tiger_Context :: _tiger.Tiger_Context
|
||||
|
||||
init :: proc(ctx: ^_tiger.Tiger_Context) {
|
||||
ctx.ver = 1
|
||||
_tiger.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) {
|
||||
_tiger.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) {
|
||||
_tiger.final(ctx, hash)
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
package tiger2
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the Tiger2 variant of the Tiger hashing algorithm as defined in <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../_tiger"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_128 :: 16
|
||||
DIGEST_SIZE_160 :: 20
|
||||
DIGEST_SIZE_192 :: 24
|
||||
|
||||
// hash_string_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte {
|
||||
return hash_bytes_128(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_128 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_128 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_128 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_128 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
hash: [DIGEST_SIZE_128]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_tiger.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_128 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_128(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_128(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_128]byte{}, false
|
||||
}
|
||||
|
||||
hash_128 :: proc {
|
||||
hash_stream_128,
|
||||
hash_file_128,
|
||||
hash_bytes_128,
|
||||
hash_string_128,
|
||||
hash_bytes_to_buffer_128,
|
||||
hash_string_to_buffer_128,
|
||||
}
|
||||
|
||||
// hash_string_160 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte {
|
||||
return hash_bytes_160(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_160 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
hash: [DIGEST_SIZE_160]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_160 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_160 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_160 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) {
|
||||
hash: [DIGEST_SIZE_160]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_tiger.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_160 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_160(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_160(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_160]byte{}, false
|
||||
}
|
||||
|
||||
hash_160 :: proc {
|
||||
hash_stream_160,
|
||||
hash_file_160,
|
||||
hash_bytes_160,
|
||||
hash_string_160,
|
||||
hash_bytes_to_buffer_160,
|
||||
hash_string_to_buffer_160,
|
||||
}
|
||||
|
||||
// hash_string_192 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte {
|
||||
return hash_bytes_192(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_192 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
||||
hash: [DIGEST_SIZE_192]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_192 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_192 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_192 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
_tiger.update(&ctx, data)
|
||||
_tiger.final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_192 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) {
|
||||
hash: [DIGEST_SIZE_192]byte
|
||||
ctx: _tiger.Tiger_Context
|
||||
ctx.ver = 2
|
||||
_tiger.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_tiger.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_tiger.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_192 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_192(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_192(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_192]byte{}, false
|
||||
}
|
||||
|
||||
hash_192 :: proc {
|
||||
hash_stream_192,
|
||||
hash_file_192,
|
||||
hash_bytes_192,
|
||||
hash_string_192,
|
||||
hash_bytes_to_buffer_192,
|
||||
hash_string_to_buffer_192,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Tiger_Context :: _tiger.Tiger_Context
|
||||
|
||||
init :: proc(ctx: ^_tiger.Tiger_Context) {
|
||||
ctx.ver = 2
|
||||
_tiger.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) {
|
||||
_tiger.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) {
|
||||
_tiger.final(ctx, hash)
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package util
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Various utility procedures
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
|
||||
// @note(bp): this can replace the other two
|
||||
cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D {
|
||||
src := src
|
||||
dst := (^mem.Raw_Slice)(&src)
|
||||
|
||||
when size_of(DE) < size_of(SE) {
|
||||
when size_of(DE) % size_of(SE) == 0 {
|
||||
dst.len /= size_of(SE) / size_of(DE)
|
||||
} else {
|
||||
dst.len *= size_of(SE)
|
||||
dst.len /= size_of(DE)
|
||||
}
|
||||
} else when size_of(DE) > size_of(SE) {
|
||||
when size_of(DE) % size_of(SE) == 0 {
|
||||
dst.len *= size_of(DE) / size_of(SE)
|
||||
} else {
|
||||
dst.len *= size_of(SE)
|
||||
dst.len /= size_of(DE)
|
||||
}
|
||||
} else when size_of(DE) != size_of(SE) {
|
||||
#assert(size_of(DE) % size_of(SE) == 0, "Different size detected")
|
||||
dst.len *= size_of(SE)
|
||||
dst.len /= size_of(DE)
|
||||
}
|
||||
|
||||
return (^D)(dst)^
|
||||
}
|
||||
|
||||
bytes_to_slice :: #force_inline proc "contextless" ($T: typeid/[]$E, bytes: []byte) -> T {
|
||||
s := transmute(mem.Raw_Slice)bytes
|
||||
s.len /= size_of(E)
|
||||
return transmute(T)s
|
||||
}
|
||||
|
||||
slice_to_bytes :: #force_inline proc "contextless" (slice: $E/[]$T) -> []byte {
|
||||
s := transmute(mem.Raw_Slice)slice
|
||||
s.len *= size_of(T)
|
||||
return transmute([]byte)s
|
||||
}
|
||||
|
||||
ROTL16 :: #force_inline proc "contextless" (a, b: u16) -> u16 {
|
||||
return ((a << b) | (a >> (16 - b)))
|
||||
}
|
||||
|
||||
ROTR16 :: #force_inline proc "contextless" (a, b: u16) -> u16 {
|
||||
return ((a >> b) | (a << (16 - b)))
|
||||
}
|
||||
|
||||
ROTL32 :: #force_inline proc "contextless"(a: u32, b: int) -> u32 {
|
||||
s := uint(b) & 31
|
||||
return (a << s) | (a >> (32 - s))
|
||||
}
|
||||
|
||||
ROTR32 :: #force_inline proc "contextless" (a: u32, b: int) -> u32 {
|
||||
s := uint(b) & 31
|
||||
return (a >> s) | (a << (32 - s))
|
||||
}
|
||||
|
||||
ROTL64 :: #force_inline proc "contextless" (a, b: u64) -> u64 {
|
||||
return ((a << b) | (a >> (64 - b)))
|
||||
}
|
||||
|
||||
ROTR64 :: #force_inline proc "contextless" (a, b: u64) -> u64 {
|
||||
return ((a >> b) | (a << (64 - b)))
|
||||
}
|
||||
|
||||
ROTL128 :: #force_inline proc "contextless" (a, b, c, d: ^u32, n: uint) {
|
||||
a, b, c, d := a, b, c, d
|
||||
t := a^ >> (32 - n)
|
||||
a^ = ((a^ << n) | (b^ >> (32 - n)))
|
||||
b^ = ((b^ << n) | (c^ >> (32 - n)))
|
||||
c^ = ((c^ << n) | (d^ >> (32 - n)))
|
||||
d^ = ((d^ << n) | t)
|
||||
}
|
||||
|
||||
U32_LE :: #force_inline proc "contextless" (b: []byte) -> u32 {
|
||||
return u32(b[0]) | u32(b[1]) << 8 | u32(b[2]) << 16 | u32(b[3]) << 24
|
||||
}
|
||||
|
||||
U64_LE :: #force_inline proc "contextless" (b: []byte) -> u64 {
|
||||
return u64(b[0]) | u64(b[1]) << 8 | u64(b[2]) << 16 | u64(b[3]) << 24 |
|
||||
u64(b[4]) << 32 | u64(b[5]) << 40 | u64(b[6]) << 48 | u64(b[7]) << 56
|
||||
}
|
||||
|
||||
U64_BE :: #force_inline proc "contextless" (b: []byte) -> u64 {
|
||||
return u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 |
|
||||
u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56
|
||||
}
|
||||
|
||||
PUT_U64_LE :: #force_inline proc "contextless" (b: []byte, v: u64) {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
b[4] = byte(v >> 32)
|
||||
b[5] = byte(v >> 40)
|
||||
b[6] = byte(v >> 48)
|
||||
b[7] = byte(v >> 56)
|
||||
}
|
||||
|
||||
PUT_U32_LE :: #force_inline proc "contextless" (b: []byte, v: u32) {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
}
|
||||
|
||||
PUT_U32_BE :: #force_inline proc "contextless" (b: []byte, v: u32) {
|
||||
b[0] = byte(v >> 24)
|
||||
b[1] = byte(v >> 16)
|
||||
b[2] = byte(v >> 8)
|
||||
b[3] = byte(v)
|
||||
}
|
||||
|
||||
PUT_U64_BE :: #force_inline proc "contextless" (b: []byte, v: u64) {
|
||||
b[0] = byte(v >> 56)
|
||||
b[1] = byte(v >> 48)
|
||||
b[2] = byte(v >> 40)
|
||||
b[3] = byte(v >> 32)
|
||||
b[4] = byte(v >> 24)
|
||||
b[5] = byte(v >> 16)
|
||||
b[6] = byte(v >> 8)
|
||||
b[7] = byte(v)
|
||||
}
|
||||
|
||||
XOR_BUF :: #force_inline proc "contextless" (input, output: []byte) {
|
||||
for i := 0; i < len(input); i += 1 {
|
||||
output[i] ~= input[i]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,806 @@
|
||||
package whirlpool
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the Whirlpool hashing algorithm, as defined in <https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE :: 64
|
||||
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Whirlpool_Context
|
||||
// init(&ctx) No-op
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Whirlpool_Context
|
||||
// init(&ctx) No-op
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Whirlpool_Context
|
||||
// init(&ctx) No-op
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
@(warning="Init is a no-op for Whirlpool")
|
||||
init :: proc(ctx: ^Whirlpool_Context) {
|
||||
// No action needed here
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Whirlpool_Context, source: []byte) {
|
||||
source_pos: int
|
||||
nn := len(source)
|
||||
source_bits := u64(nn * 8)
|
||||
source_gap := u32((8 - (int(source_bits & 7))) & 7)
|
||||
buffer_rem := uint(ctx.buffer_bits & 7)
|
||||
b: u32
|
||||
|
||||
for i, carry, value := 31, u32(0), u32(source_bits); i >= 0 && (carry != 0 || value != 0); i -= 1 {
|
||||
carry += u32(ctx.bitlength[i]) + (u32(value & 0xff))
|
||||
ctx.bitlength[i] = byte(carry)
|
||||
carry >>= 8
|
||||
value >>= 8
|
||||
}
|
||||
|
||||
for source_bits > 8 {
|
||||
b = u32(u32((source[source_pos] << source_gap) & 0xff) | u32((source[source_pos+1] & 0xff) >> (8 - source_gap)))
|
||||
|
||||
ctx.buffer[ctx.buffer_pos] |= u8(b >> buffer_rem)
|
||||
ctx.buffer_pos += 1
|
||||
ctx.buffer_bits += int(8 - buffer_rem)
|
||||
|
||||
if ctx.buffer_bits == 512 {
|
||||
transform(ctx)
|
||||
ctx.buffer_bits = 0
|
||||
ctx.buffer_pos = 0
|
||||
}
|
||||
ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem))
|
||||
ctx.buffer_bits += int(buffer_rem)
|
||||
source_bits -= 8
|
||||
source_pos += 1
|
||||
}
|
||||
|
||||
if source_bits > 0 {
|
||||
b = u32((source[source_pos] << source_gap) & 0xff)
|
||||
ctx.buffer[ctx.buffer_pos] |= byte(b) >> buffer_rem
|
||||
} else {b = 0}
|
||||
|
||||
if u64(buffer_rem) + source_bits < 8 {
|
||||
ctx.buffer_bits += int(source_bits)
|
||||
} else {
|
||||
ctx.buffer_pos += 1
|
||||
ctx.buffer_bits += 8 - int(buffer_rem)
|
||||
source_bits -= u64(8 - buffer_rem)
|
||||
|
||||
if ctx.buffer_bits == 512 {
|
||||
transform(ctx)
|
||||
ctx.buffer_bits = 0
|
||||
ctx.buffer_pos = 0
|
||||
}
|
||||
ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem))
|
||||
ctx.buffer_bits += int(source_bits)
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Whirlpool_Context, hash: []byte) {
|
||||
n := ctx
|
||||
n.buffer[n.buffer_pos] |= 0x80 >> (uint(n.buffer_bits) & 7)
|
||||
n.buffer_pos += 1
|
||||
|
||||
if n.buffer_pos > 64 - 32 {
|
||||
if n.buffer_pos < 64 {
|
||||
for i := 0; i < 64 - n.buffer_pos; i += 1 {
|
||||
n.buffer[n.buffer_pos + i] = 0
|
||||
}
|
||||
}
|
||||
transform(ctx)
|
||||
n.buffer_pos = 0
|
||||
}
|
||||
|
||||
if n.buffer_pos < 64 - 32 {
|
||||
for i := 0; i < (64 - 32) - n.buffer_pos; i += 1 {
|
||||
n.buffer[n.buffer_pos + i] = 0
|
||||
}
|
||||
}
|
||||
n.buffer_pos = 64 - 32
|
||||
|
||||
for i := 0; i < 32; i += 1 {
|
||||
n.buffer[n.buffer_pos + i] = n.bitlength[i]
|
||||
}
|
||||
transform(ctx)
|
||||
|
||||
for i := 0; i < 8; i += 1 {
|
||||
hash[i * 8] = byte(n.hash[i] >> 56)
|
||||
hash[i * 8 + 1] = byte(n.hash[i] >> 48)
|
||||
hash[i * 8 + 2] = byte(n.hash[i] >> 40)
|
||||
hash[i * 8 + 3] = byte(n.hash[i] >> 32)
|
||||
hash[i * 8 + 4] = byte(n.hash[i] >> 24)
|
||||
hash[i * 8 + 5] = byte(n.hash[i] >> 16)
|
||||
hash[i * 8 + 6] = byte(n.hash[i] >> 8)
|
||||
hash[i * 8 + 7] = byte(n.hash[i])
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Whirlpool implementation
|
||||
*/
|
||||
|
||||
ROUNDS :: 10
|
||||
|
||||
Whirlpool_Context :: struct {
|
||||
bitlength: [32]byte,
|
||||
buffer: [64]byte,
|
||||
buffer_bits: int,
|
||||
buffer_pos: int,
|
||||
hash: [8]u64,
|
||||
}
|
||||
|
||||
C0 := [256]u64 {
|
||||
0x18186018c07830d8, 0x23238c2305af4626, 0xc6c63fc67ef991b8, 0xe8e887e8136fcdfb,
|
||||
0x878726874ca113cb, 0xb8b8dab8a9626d11, 0x0101040108050209, 0x4f4f214f426e9e0d,
|
||||
0x3636d836adee6c9b, 0xa6a6a2a6590451ff, 0xd2d26fd2debdb90c, 0xf5f5f3f5fb06f70e,
|
||||
0x7979f979ef80f296, 0x6f6fa16f5fcede30, 0x91917e91fcef3f6d, 0x52525552aa07a4f8,
|
||||
0x60609d6027fdc047, 0xbcbccabc89766535, 0x9b9b569baccd2b37, 0x8e8e028e048c018a,
|
||||
0xa3a3b6a371155bd2, 0x0c0c300c603c186c, 0x7b7bf17bff8af684, 0x3535d435b5e16a80,
|
||||
0x1d1d741de8693af5, 0xe0e0a7e05347ddb3, 0xd7d77bd7f6acb321, 0xc2c22fc25eed999c,
|
||||
0x2e2eb82e6d965c43, 0x4b4b314b627a9629, 0xfefedffea321e15d, 0x575741578216aed5,
|
||||
0x15155415a8412abd, 0x7777c1779fb6eee8, 0x3737dc37a5eb6e92, 0xe5e5b3e57b56d79e,
|
||||
0x9f9f469f8cd92313, 0xf0f0e7f0d317fd23, 0x4a4a354a6a7f9420, 0xdada4fda9e95a944,
|
||||
0x58587d58fa25b0a2, 0xc9c903c906ca8fcf, 0x2929a429558d527c, 0x0a0a280a5022145a,
|
||||
0xb1b1feb1e14f7f50, 0xa0a0baa0691a5dc9, 0x6b6bb16b7fdad614, 0x85852e855cab17d9,
|
||||
0xbdbdcebd8173673c, 0x5d5d695dd234ba8f, 0x1010401080502090, 0xf4f4f7f4f303f507,
|
||||
0xcbcb0bcb16c08bdd, 0x3e3ef83eedc67cd3, 0x0505140528110a2d, 0x676781671fe6ce78,
|
||||
0xe4e4b7e47353d597, 0x27279c2725bb4e02, 0x4141194132588273, 0x8b8b168b2c9d0ba7,
|
||||
0xa7a7a6a7510153f6, 0x7d7de97dcf94fab2, 0x95956e95dcfb3749, 0xd8d847d88e9fad56,
|
||||
0xfbfbcbfb8b30eb70, 0xeeee9fee2371c1cd, 0x7c7ced7cc791f8bb, 0x6666856617e3cc71,
|
||||
0xdddd53dda68ea77b, 0x17175c17b84b2eaf, 0x4747014702468e45, 0x9e9e429e84dc211a,
|
||||
0xcaca0fca1ec589d4, 0x2d2db42d75995a58, 0xbfbfc6bf9179632e, 0x07071c07381b0e3f,
|
||||
0xadad8ead012347ac, 0x5a5a755aea2fb4b0, 0x838336836cb51bef, 0x3333cc3385ff66b6,
|
||||
0x636391633ff2c65c, 0x02020802100a0412, 0xaaaa92aa39384993, 0x7171d971afa8e2de,
|
||||
0xc8c807c80ecf8dc6, 0x19196419c87d32d1, 0x494939497270923b, 0xd9d943d9869aaf5f,
|
||||
0xf2f2eff2c31df931, 0xe3e3abe34b48dba8, 0x5b5b715be22ab6b9, 0x88881a8834920dbc,
|
||||
0x9a9a529aa4c8293e, 0x262698262dbe4c0b, 0x3232c8328dfa64bf, 0xb0b0fab0e94a7d59,
|
||||
0xe9e983e91b6acff2, 0x0f0f3c0f78331e77, 0xd5d573d5e6a6b733, 0x80803a8074ba1df4,
|
||||
0xbebec2be997c6127, 0xcdcd13cd26de87eb, 0x3434d034bde46889, 0x48483d487a759032,
|
||||
0xffffdbffab24e354, 0x7a7af57af78ff48d, 0x90907a90f4ea3d64, 0x5f5f615fc23ebe9d,
|
||||
0x202080201da0403d, 0x6868bd6867d5d00f, 0x1a1a681ad07234ca, 0xaeae82ae192c41b7,
|
||||
0xb4b4eab4c95e757d, 0x54544d549a19a8ce, 0x93937693ece53b7f, 0x222288220daa442f,
|
||||
0x64648d6407e9c863, 0xf1f1e3f1db12ff2a, 0x7373d173bfa2e6cc, 0x12124812905a2482,
|
||||
0x40401d403a5d807a, 0x0808200840281048, 0xc3c32bc356e89b95, 0xecec97ec337bc5df,
|
||||
0xdbdb4bdb9690ab4d, 0xa1a1bea1611f5fc0, 0x8d8d0e8d1c830791, 0x3d3df43df5c97ac8,
|
||||
0x97976697ccf1335b, 0x0000000000000000, 0xcfcf1bcf36d483f9, 0x2b2bac2b4587566e,
|
||||
0x7676c57697b3ece1, 0x8282328264b019e6, 0xd6d67fd6fea9b128, 0x1b1b6c1bd87736c3,
|
||||
0xb5b5eeb5c15b7774, 0xafaf86af112943be, 0x6a6ab56a77dfd41d, 0x50505d50ba0da0ea,
|
||||
0x45450945124c8a57, 0xf3f3ebf3cb18fb38, 0x3030c0309df060ad, 0xefef9bef2b74c3c4,
|
||||
0x3f3ffc3fe5c37eda, 0x55554955921caac7, 0xa2a2b2a2791059db, 0xeaea8fea0365c9e9,
|
||||
0x656589650fecca6a, 0xbabad2bab9686903, 0x2f2fbc2f65935e4a, 0xc0c027c04ee79d8e,
|
||||
0xdede5fdebe81a160, 0x1c1c701ce06c38fc, 0xfdfdd3fdbb2ee746, 0x4d4d294d52649a1f,
|
||||
0x92927292e4e03976, 0x7575c9758fbceafa, 0x06061806301e0c36, 0x8a8a128a249809ae,
|
||||
0xb2b2f2b2f940794b, 0xe6e6bfe66359d185, 0x0e0e380e70361c7e, 0x1f1f7c1ff8633ee7,
|
||||
0x6262956237f7c455, 0xd4d477d4eea3b53a, 0xa8a89aa829324d81, 0x96966296c4f43152,
|
||||
0xf9f9c3f99b3aef62, 0xc5c533c566f697a3, 0x2525942535b14a10, 0x59597959f220b2ab,
|
||||
0x84842a8454ae15d0, 0x7272d572b7a7e4c5, 0x3939e439d5dd72ec, 0x4c4c2d4c5a619816,
|
||||
0x5e5e655eca3bbc94, 0x7878fd78e785f09f, 0x3838e038ddd870e5, 0x8c8c0a8c14860598,
|
||||
0xd1d163d1c6b2bf17, 0xa5a5aea5410b57e4, 0xe2e2afe2434dd9a1, 0x616199612ff8c24e,
|
||||
0xb3b3f6b3f1457b42, 0x2121842115a54234, 0x9c9c4a9c94d62508, 0x1e1e781ef0663cee,
|
||||
0x4343114322528661, 0xc7c73bc776fc93b1, 0xfcfcd7fcb32be54f, 0x0404100420140824,
|
||||
0x51515951b208a2e3, 0x99995e99bcc72f25, 0x6d6da96d4fc4da22, 0x0d0d340d68391a65,
|
||||
0xfafacffa8335e979, 0xdfdf5bdfb684a369, 0x7e7ee57ed79bfca9, 0x242490243db44819,
|
||||
0x3b3bec3bc5d776fe, 0xabab96ab313d4b9a, 0xcece1fce3ed181f0, 0x1111441188552299,
|
||||
0x8f8f068f0c890383, 0x4e4e254e4a6b9c04, 0xb7b7e6b7d1517366, 0xebeb8beb0b60cbe0,
|
||||
0x3c3cf03cfdcc78c1, 0x81813e817cbf1ffd, 0x94946a94d4fe3540, 0xf7f7fbf7eb0cf31c,
|
||||
0xb9b9deb9a1676f18, 0x13134c13985f268b, 0x2c2cb02c7d9c5851, 0xd3d36bd3d6b8bb05,
|
||||
0xe7e7bbe76b5cd38c, 0x6e6ea56e57cbdc39, 0xc4c437c46ef395aa, 0x03030c03180f061b,
|
||||
0x565645568a13acdc, 0x44440d441a49885e, 0x7f7fe17fdf9efea0, 0xa9a99ea921374f88,
|
||||
0x2a2aa82a4d825467, 0xbbbbd6bbb16d6b0a, 0xc1c123c146e29f87, 0x53535153a202a6f1,
|
||||
0xdcdc57dcae8ba572, 0x0b0b2c0b58271653, 0x9d9d4e9d9cd32701, 0x6c6cad6c47c1d82b,
|
||||
0x3131c43195f562a4, 0x7474cd7487b9e8f3, 0xf6f6fff6e309f115, 0x464605460a438c4c,
|
||||
0xacac8aac092645a5, 0x89891e893c970fb5, 0x14145014a04428b4, 0xe1e1a3e15b42dfba,
|
||||
0x16165816b04e2ca6, 0x3a3ae83acdd274f7, 0x6969b9696fd0d206, 0x09092409482d1241,
|
||||
0x7070dd70a7ade0d7, 0xb6b6e2b6d954716f, 0xd0d067d0ceb7bd1e, 0xeded93ed3b7ec7d6,
|
||||
0xcccc17cc2edb85e2, 0x424215422a578468, 0x98985a98b4c22d2c, 0xa4a4aaa4490e55ed,
|
||||
0x2828a0285d885075, 0x5c5c6d5cda31b886, 0xf8f8c7f8933fed6b, 0x8686228644a411c2,
|
||||
}
|
||||
|
||||
C1 := [256]u64 {
|
||||
0xd818186018c07830, 0x2623238c2305af46, 0xb8c6c63fc67ef991, 0xfbe8e887e8136fcd,
|
||||
0xcb878726874ca113, 0x11b8b8dab8a9626d, 0x0901010401080502, 0x0d4f4f214f426e9e,
|
||||
0x9b3636d836adee6c, 0xffa6a6a2a6590451, 0x0cd2d26fd2debdb9, 0x0ef5f5f3f5fb06f7,
|
||||
0x967979f979ef80f2, 0x306f6fa16f5fcede, 0x6d91917e91fcef3f, 0xf852525552aa07a4,
|
||||
0x4760609d6027fdc0, 0x35bcbccabc897665, 0x379b9b569baccd2b, 0x8a8e8e028e048c01,
|
||||
0xd2a3a3b6a371155b, 0x6c0c0c300c603c18, 0x847b7bf17bff8af6, 0x803535d435b5e16a,
|
||||
0xf51d1d741de8693a, 0xb3e0e0a7e05347dd, 0x21d7d77bd7f6acb3, 0x9cc2c22fc25eed99,
|
||||
0x432e2eb82e6d965c, 0x294b4b314b627a96, 0x5dfefedffea321e1, 0xd5575741578216ae,
|
||||
0xbd15155415a8412a, 0xe87777c1779fb6ee, 0x923737dc37a5eb6e, 0x9ee5e5b3e57b56d7,
|
||||
0x139f9f469f8cd923, 0x23f0f0e7f0d317fd, 0x204a4a354a6a7f94, 0x44dada4fda9e95a9,
|
||||
0xa258587d58fa25b0, 0xcfc9c903c906ca8f, 0x7c2929a429558d52, 0x5a0a0a280a502214,
|
||||
0x50b1b1feb1e14f7f, 0xc9a0a0baa0691a5d, 0x146b6bb16b7fdad6, 0xd985852e855cab17,
|
||||
0x3cbdbdcebd817367, 0x8f5d5d695dd234ba, 0x9010104010805020, 0x07f4f4f7f4f303f5,
|
||||
0xddcbcb0bcb16c08b, 0xd33e3ef83eedc67c, 0x2d0505140528110a, 0x78676781671fe6ce,
|
||||
0x97e4e4b7e47353d5, 0x0227279c2725bb4e, 0x7341411941325882, 0xa78b8b168b2c9d0b,
|
||||
0xf6a7a7a6a7510153, 0xb27d7de97dcf94fa, 0x4995956e95dcfb37, 0x56d8d847d88e9fad,
|
||||
0x70fbfbcbfb8b30eb, 0xcdeeee9fee2371c1, 0xbb7c7ced7cc791f8, 0x716666856617e3cc,
|
||||
0x7bdddd53dda68ea7, 0xaf17175c17b84b2e, 0x454747014702468e, 0x1a9e9e429e84dc21,
|
||||
0xd4caca0fca1ec589, 0x582d2db42d75995a, 0x2ebfbfc6bf917963, 0x3f07071c07381b0e,
|
||||
0xacadad8ead012347, 0xb05a5a755aea2fb4, 0xef838336836cb51b, 0xb63333cc3385ff66,
|
||||
0x5c636391633ff2c6, 0x1202020802100a04, 0x93aaaa92aa393849, 0xde7171d971afa8e2,
|
||||
0xc6c8c807c80ecf8d, 0xd119196419c87d32, 0x3b49493949727092, 0x5fd9d943d9869aaf,
|
||||
0x31f2f2eff2c31df9, 0xa8e3e3abe34b48db, 0xb95b5b715be22ab6, 0xbc88881a8834920d,
|
||||
0x3e9a9a529aa4c829, 0x0b262698262dbe4c, 0xbf3232c8328dfa64, 0x59b0b0fab0e94a7d,
|
||||
0xf2e9e983e91b6acf, 0x770f0f3c0f78331e, 0x33d5d573d5e6a6b7, 0xf480803a8074ba1d,
|
||||
0x27bebec2be997c61, 0xebcdcd13cd26de87, 0x893434d034bde468, 0x3248483d487a7590,
|
||||
0x54ffffdbffab24e3, 0x8d7a7af57af78ff4, 0x6490907a90f4ea3d, 0x9d5f5f615fc23ebe,
|
||||
0x3d202080201da040, 0x0f6868bd6867d5d0, 0xca1a1a681ad07234, 0xb7aeae82ae192c41,
|
||||
0x7db4b4eab4c95e75, 0xce54544d549a19a8, 0x7f93937693ece53b, 0x2f222288220daa44,
|
||||
0x6364648d6407e9c8, 0x2af1f1e3f1db12ff, 0xcc7373d173bfa2e6, 0x8212124812905a24,
|
||||
0x7a40401d403a5d80, 0x4808082008402810, 0x95c3c32bc356e89b, 0xdfecec97ec337bc5,
|
||||
0x4ddbdb4bdb9690ab, 0xc0a1a1bea1611f5f, 0x918d8d0e8d1c8307, 0xc83d3df43df5c97a,
|
||||
0x5b97976697ccf133, 0x0000000000000000, 0xf9cfcf1bcf36d483, 0x6e2b2bac2b458756,
|
||||
0xe17676c57697b3ec, 0xe68282328264b019, 0x28d6d67fd6fea9b1, 0xc31b1b6c1bd87736,
|
||||
0x74b5b5eeb5c15b77, 0xbeafaf86af112943, 0x1d6a6ab56a77dfd4, 0xea50505d50ba0da0,
|
||||
0x5745450945124c8a, 0x38f3f3ebf3cb18fb, 0xad3030c0309df060, 0xc4efef9bef2b74c3,
|
||||
0xda3f3ffc3fe5c37e, 0xc755554955921caa, 0xdba2a2b2a2791059, 0xe9eaea8fea0365c9,
|
||||
0x6a656589650fecca, 0x03babad2bab96869, 0x4a2f2fbc2f65935e, 0x8ec0c027c04ee79d,
|
||||
0x60dede5fdebe81a1, 0xfc1c1c701ce06c38, 0x46fdfdd3fdbb2ee7, 0x1f4d4d294d52649a,
|
||||
0x7692927292e4e039, 0xfa7575c9758fbcea, 0x3606061806301e0c, 0xae8a8a128a249809,
|
||||
0x4bb2b2f2b2f94079, 0x85e6e6bfe66359d1, 0x7e0e0e380e70361c, 0xe71f1f7c1ff8633e,
|
||||
0x556262956237f7c4, 0x3ad4d477d4eea3b5, 0x81a8a89aa829324d, 0x5296966296c4f431,
|
||||
0x62f9f9c3f99b3aef, 0xa3c5c533c566f697, 0x102525942535b14a, 0xab59597959f220b2,
|
||||
0xd084842a8454ae15, 0xc57272d572b7a7e4, 0xec3939e439d5dd72, 0x164c4c2d4c5a6198,
|
||||
0x945e5e655eca3bbc, 0x9f7878fd78e785f0, 0xe53838e038ddd870, 0x988c8c0a8c148605,
|
||||
0x17d1d163d1c6b2bf, 0xe4a5a5aea5410b57, 0xa1e2e2afe2434dd9, 0x4e616199612ff8c2,
|
||||
0x42b3b3f6b3f1457b, 0x342121842115a542, 0x089c9c4a9c94d625, 0xee1e1e781ef0663c,
|
||||
0x6143431143225286, 0xb1c7c73bc776fc93, 0x4ffcfcd7fcb32be5, 0x2404041004201408,
|
||||
0xe351515951b208a2, 0x2599995e99bcc72f, 0x226d6da96d4fc4da, 0x650d0d340d68391a,
|
||||
0x79fafacffa8335e9, 0x69dfdf5bdfb684a3, 0xa97e7ee57ed79bfc, 0x19242490243db448,
|
||||
0xfe3b3bec3bc5d776, 0x9aabab96ab313d4b, 0xf0cece1fce3ed181, 0x9911114411885522,
|
||||
0x838f8f068f0c8903, 0x044e4e254e4a6b9c, 0x66b7b7e6b7d15173, 0xe0ebeb8beb0b60cb,
|
||||
0xc13c3cf03cfdcc78, 0xfd81813e817cbf1f, 0x4094946a94d4fe35, 0x1cf7f7fbf7eb0cf3,
|
||||
0x18b9b9deb9a1676f, 0x8b13134c13985f26, 0x512c2cb02c7d9c58, 0x05d3d36bd3d6b8bb,
|
||||
0x8ce7e7bbe76b5cd3, 0x396e6ea56e57cbdc, 0xaac4c437c46ef395, 0x1b03030c03180f06,
|
||||
0xdc565645568a13ac, 0x5e44440d441a4988, 0xa07f7fe17fdf9efe, 0x88a9a99ea921374f,
|
||||
0x672a2aa82a4d8254, 0x0abbbbd6bbb16d6b, 0x87c1c123c146e29f, 0xf153535153a202a6,
|
||||
0x72dcdc57dcae8ba5, 0x530b0b2c0b582716, 0x019d9d4e9d9cd327, 0x2b6c6cad6c47c1d8,
|
||||
0xa43131c43195f562, 0xf37474cd7487b9e8, 0x15f6f6fff6e309f1, 0x4c464605460a438c,
|
||||
0xa5acac8aac092645, 0xb589891e893c970f, 0xb414145014a04428, 0xbae1e1a3e15b42df,
|
||||
0xa616165816b04e2c, 0xf73a3ae83acdd274, 0x066969b9696fd0d2, 0x4109092409482d12,
|
||||
0xd77070dd70a7ade0, 0x6fb6b6e2b6d95471, 0x1ed0d067d0ceb7bd, 0xd6eded93ed3b7ec7,
|
||||
0xe2cccc17cc2edb85, 0x68424215422a5784, 0x2c98985a98b4c22d, 0xeda4a4aaa4490e55,
|
||||
0x752828a0285d8850, 0x865c5c6d5cda31b8, 0x6bf8f8c7f8933fed, 0xc28686228644a411,
|
||||
}
|
||||
|
||||
C2 := [256]u64 {
|
||||
0x30d818186018c078, 0x462623238c2305af, 0x91b8c6c63fc67ef9, 0xcdfbe8e887e8136f,
|
||||
0x13cb878726874ca1, 0x6d11b8b8dab8a962, 0x0209010104010805, 0x9e0d4f4f214f426e,
|
||||
0x6c9b3636d836adee, 0x51ffa6a6a2a65904, 0xb90cd2d26fd2debd, 0xf70ef5f5f3f5fb06,
|
||||
0xf2967979f979ef80, 0xde306f6fa16f5fce, 0x3f6d91917e91fcef, 0xa4f852525552aa07,
|
||||
0xc04760609d6027fd, 0x6535bcbccabc8976, 0x2b379b9b569baccd, 0x018a8e8e028e048c,
|
||||
0x5bd2a3a3b6a37115, 0x186c0c0c300c603c, 0xf6847b7bf17bff8a, 0x6a803535d435b5e1,
|
||||
0x3af51d1d741de869, 0xddb3e0e0a7e05347, 0xb321d7d77bd7f6ac, 0x999cc2c22fc25eed,
|
||||
0x5c432e2eb82e6d96, 0x96294b4b314b627a, 0xe15dfefedffea321, 0xaed5575741578216,
|
||||
0x2abd15155415a841, 0xeee87777c1779fb6, 0x6e923737dc37a5eb, 0xd79ee5e5b3e57b56,
|
||||
0x23139f9f469f8cd9, 0xfd23f0f0e7f0d317, 0x94204a4a354a6a7f, 0xa944dada4fda9e95,
|
||||
0xb0a258587d58fa25, 0x8fcfc9c903c906ca, 0x527c2929a429558d, 0x145a0a0a280a5022,
|
||||
0x7f50b1b1feb1e14f, 0x5dc9a0a0baa0691a, 0xd6146b6bb16b7fda, 0x17d985852e855cab,
|
||||
0x673cbdbdcebd8173, 0xba8f5d5d695dd234, 0x2090101040108050, 0xf507f4f4f7f4f303,
|
||||
0x8bddcbcb0bcb16c0, 0x7cd33e3ef83eedc6, 0x0a2d050514052811, 0xce78676781671fe6,
|
||||
0xd597e4e4b7e47353, 0x4e0227279c2725bb, 0x8273414119413258, 0x0ba78b8b168b2c9d,
|
||||
0x53f6a7a7a6a75101, 0xfab27d7de97dcf94, 0x374995956e95dcfb, 0xad56d8d847d88e9f,
|
||||
0xeb70fbfbcbfb8b30, 0xc1cdeeee9fee2371, 0xf8bb7c7ced7cc791, 0xcc716666856617e3,
|
||||
0xa77bdddd53dda68e, 0x2eaf17175c17b84b, 0x8e45474701470246, 0x211a9e9e429e84dc,
|
||||
0x89d4caca0fca1ec5, 0x5a582d2db42d7599, 0x632ebfbfc6bf9179, 0x0e3f07071c07381b,
|
||||
0x47acadad8ead0123, 0xb4b05a5a755aea2f, 0x1bef838336836cb5, 0x66b63333cc3385ff,
|
||||
0xc65c636391633ff2, 0x041202020802100a, 0x4993aaaa92aa3938, 0xe2de7171d971afa8,
|
||||
0x8dc6c8c807c80ecf, 0x32d119196419c87d, 0x923b494939497270, 0xaf5fd9d943d9869a,
|
||||
0xf931f2f2eff2c31d, 0xdba8e3e3abe34b48, 0xb6b95b5b715be22a, 0x0dbc88881a883492,
|
||||
0x293e9a9a529aa4c8, 0x4c0b262698262dbe, 0x64bf3232c8328dfa, 0x7d59b0b0fab0e94a,
|
||||
0xcff2e9e983e91b6a, 0x1e770f0f3c0f7833, 0xb733d5d573d5e6a6, 0x1df480803a8074ba,
|
||||
0x6127bebec2be997c, 0x87ebcdcd13cd26de, 0x68893434d034bde4, 0x903248483d487a75,
|
||||
0xe354ffffdbffab24, 0xf48d7a7af57af78f, 0x3d6490907a90f4ea, 0xbe9d5f5f615fc23e,
|
||||
0x403d202080201da0, 0xd00f6868bd6867d5, 0x34ca1a1a681ad072, 0x41b7aeae82ae192c,
|
||||
0x757db4b4eab4c95e, 0xa8ce54544d549a19, 0x3b7f93937693ece5, 0x442f222288220daa,
|
||||
0xc86364648d6407e9, 0xff2af1f1e3f1db12, 0xe6cc7373d173bfa2, 0x248212124812905a,
|
||||
0x807a40401d403a5d, 0x1048080820084028, 0x9b95c3c32bc356e8, 0xc5dfecec97ec337b,
|
||||
0xab4ddbdb4bdb9690, 0x5fc0a1a1bea1611f, 0x07918d8d0e8d1c83, 0x7ac83d3df43df5c9,
|
||||
0x335b97976697ccf1, 0x0000000000000000, 0x83f9cfcf1bcf36d4, 0x566e2b2bac2b4587,
|
||||
0xece17676c57697b3, 0x19e68282328264b0, 0xb128d6d67fd6fea9, 0x36c31b1b6c1bd877,
|
||||
0x7774b5b5eeb5c15b, 0x43beafaf86af1129, 0xd41d6a6ab56a77df, 0xa0ea50505d50ba0d,
|
||||
0x8a5745450945124c, 0xfb38f3f3ebf3cb18, 0x60ad3030c0309df0, 0xc3c4efef9bef2b74,
|
||||
0x7eda3f3ffc3fe5c3, 0xaac755554955921c, 0x59dba2a2b2a27910, 0xc9e9eaea8fea0365,
|
||||
0xca6a656589650fec, 0x6903babad2bab968, 0x5e4a2f2fbc2f6593, 0x9d8ec0c027c04ee7,
|
||||
0xa160dede5fdebe81, 0x38fc1c1c701ce06c, 0xe746fdfdd3fdbb2e, 0x9a1f4d4d294d5264,
|
||||
0x397692927292e4e0, 0xeafa7575c9758fbc, 0x0c3606061806301e, 0x09ae8a8a128a2498,
|
||||
0x794bb2b2f2b2f940, 0xd185e6e6bfe66359, 0x1c7e0e0e380e7036, 0x3ee71f1f7c1ff863,
|
||||
0xc4556262956237f7, 0xb53ad4d477d4eea3, 0x4d81a8a89aa82932, 0x315296966296c4f4,
|
||||
0xef62f9f9c3f99b3a, 0x97a3c5c533c566f6, 0x4a102525942535b1, 0xb2ab59597959f220,
|
||||
0x15d084842a8454ae, 0xe4c57272d572b7a7, 0x72ec3939e439d5dd, 0x98164c4c2d4c5a61,
|
||||
0xbc945e5e655eca3b, 0xf09f7878fd78e785, 0x70e53838e038ddd8, 0x05988c8c0a8c1486,
|
||||
0xbf17d1d163d1c6b2, 0x57e4a5a5aea5410b, 0xd9a1e2e2afe2434d, 0xc24e616199612ff8,
|
||||
0x7b42b3b3f6b3f145, 0x42342121842115a5, 0x25089c9c4a9c94d6, 0x3cee1e1e781ef066,
|
||||
0x8661434311432252, 0x93b1c7c73bc776fc, 0xe54ffcfcd7fcb32b, 0x0824040410042014,
|
||||
0xa2e351515951b208, 0x2f2599995e99bcc7, 0xda226d6da96d4fc4, 0x1a650d0d340d6839,
|
||||
0xe979fafacffa8335, 0xa369dfdf5bdfb684, 0xfca97e7ee57ed79b, 0x4819242490243db4,
|
||||
0x76fe3b3bec3bc5d7, 0x4b9aabab96ab313d, 0x81f0cece1fce3ed1, 0x2299111144118855,
|
||||
0x03838f8f068f0c89, 0x9c044e4e254e4a6b, 0x7366b7b7e6b7d151, 0xcbe0ebeb8beb0b60,
|
||||
0x78c13c3cf03cfdcc, 0x1ffd81813e817cbf, 0x354094946a94d4fe, 0xf31cf7f7fbf7eb0c,
|
||||
0x6f18b9b9deb9a167, 0x268b13134c13985f, 0x58512c2cb02c7d9c, 0xbb05d3d36bd3d6b8,
|
||||
0xd38ce7e7bbe76b5c, 0xdc396e6ea56e57cb, 0x95aac4c437c46ef3, 0x061b03030c03180f,
|
||||
0xacdc565645568a13, 0x885e44440d441a49, 0xfea07f7fe17fdf9e, 0x4f88a9a99ea92137,
|
||||
0x54672a2aa82a4d82, 0x6b0abbbbd6bbb16d, 0x9f87c1c123c146e2, 0xa6f153535153a202,
|
||||
0xa572dcdc57dcae8b, 0x16530b0b2c0b5827, 0x27019d9d4e9d9cd3, 0xd82b6c6cad6c47c1,
|
||||
0x62a43131c43195f5, 0xe8f37474cd7487b9, 0xf115f6f6fff6e309, 0x8c4c464605460a43,
|
||||
0x45a5acac8aac0926, 0x0fb589891e893c97, 0x28b414145014a044, 0xdfbae1e1a3e15b42,
|
||||
0x2ca616165816b04e, 0x74f73a3ae83acdd2, 0xd2066969b9696fd0, 0x124109092409482d,
|
||||
0xe0d77070dd70a7ad, 0x716fb6b6e2b6d954, 0xbd1ed0d067d0ceb7, 0xc7d6eded93ed3b7e,
|
||||
0x85e2cccc17cc2edb, 0x8468424215422a57, 0x2d2c98985a98b4c2, 0x55eda4a4aaa4490e,
|
||||
0x50752828a0285d88, 0xb8865c5c6d5cda31, 0xed6bf8f8c7f8933f, 0x11c28686228644a4,
|
||||
}
|
||||
|
||||
C3 := [256]u64 {
|
||||
0x7830d818186018c0, 0xaf462623238c2305, 0xf991b8c6c63fc67e, 0x6fcdfbe8e887e813,
|
||||
0xa113cb878726874c, 0x626d11b8b8dab8a9, 0x0502090101040108, 0x6e9e0d4f4f214f42,
|
||||
0xee6c9b3636d836ad, 0x0451ffa6a6a2a659, 0xbdb90cd2d26fd2de, 0x06f70ef5f5f3f5fb,
|
||||
0x80f2967979f979ef, 0xcede306f6fa16f5f, 0xef3f6d91917e91fc, 0x07a4f852525552aa,
|
||||
0xfdc04760609d6027, 0x766535bcbccabc89, 0xcd2b379b9b569bac, 0x8c018a8e8e028e04,
|
||||
0x155bd2a3a3b6a371, 0x3c186c0c0c300c60, 0x8af6847b7bf17bff, 0xe16a803535d435b5,
|
||||
0x693af51d1d741de8, 0x47ddb3e0e0a7e053, 0xacb321d7d77bd7f6, 0xed999cc2c22fc25e,
|
||||
0x965c432e2eb82e6d, 0x7a96294b4b314b62, 0x21e15dfefedffea3, 0x16aed55757415782,
|
||||
0x412abd15155415a8, 0xb6eee87777c1779f, 0xeb6e923737dc37a5, 0x56d79ee5e5b3e57b,
|
||||
0xd923139f9f469f8c, 0x17fd23f0f0e7f0d3, 0x7f94204a4a354a6a, 0x95a944dada4fda9e,
|
||||
0x25b0a258587d58fa, 0xca8fcfc9c903c906, 0x8d527c2929a42955, 0x22145a0a0a280a50,
|
||||
0x4f7f50b1b1feb1e1, 0x1a5dc9a0a0baa069, 0xdad6146b6bb16b7f, 0xab17d985852e855c,
|
||||
0x73673cbdbdcebd81, 0x34ba8f5d5d695dd2, 0x5020901010401080, 0x03f507f4f4f7f4f3,
|
||||
0xc08bddcbcb0bcb16, 0xc67cd33e3ef83eed, 0x110a2d0505140528, 0xe6ce78676781671f,
|
||||
0x53d597e4e4b7e473, 0xbb4e0227279c2725, 0x5882734141194132, 0x9d0ba78b8b168b2c,
|
||||
0x0153f6a7a7a6a751, 0x94fab27d7de97dcf, 0xfb374995956e95dc, 0x9fad56d8d847d88e,
|
||||
0x30eb70fbfbcbfb8b, 0x71c1cdeeee9fee23, 0x91f8bb7c7ced7cc7, 0xe3cc716666856617,
|
||||
0x8ea77bdddd53dda6, 0x4b2eaf17175c17b8, 0x468e454747014702, 0xdc211a9e9e429e84,
|
||||
0xc589d4caca0fca1e, 0x995a582d2db42d75, 0x79632ebfbfc6bf91, 0x1b0e3f07071c0738,
|
||||
0x2347acadad8ead01, 0x2fb4b05a5a755aea, 0xb51bef838336836c, 0xff66b63333cc3385,
|
||||
0xf2c65c636391633f, 0x0a04120202080210, 0x384993aaaa92aa39, 0xa8e2de7171d971af,
|
||||
0xcf8dc6c8c807c80e, 0x7d32d119196419c8, 0x70923b4949394972, 0x9aaf5fd9d943d986,
|
||||
0x1df931f2f2eff2c3, 0x48dba8e3e3abe34b, 0x2ab6b95b5b715be2, 0x920dbc88881a8834,
|
||||
0xc8293e9a9a529aa4, 0xbe4c0b262698262d, 0xfa64bf3232c8328d, 0x4a7d59b0b0fab0e9,
|
||||
0x6acff2e9e983e91b, 0x331e770f0f3c0f78, 0xa6b733d5d573d5e6, 0xba1df480803a8074,
|
||||
0x7c6127bebec2be99, 0xde87ebcdcd13cd26, 0xe468893434d034bd, 0x75903248483d487a,
|
||||
0x24e354ffffdbffab, 0x8ff48d7a7af57af7, 0xea3d6490907a90f4, 0x3ebe9d5f5f615fc2,
|
||||
0xa0403d202080201d, 0xd5d00f6868bd6867, 0x7234ca1a1a681ad0, 0x2c41b7aeae82ae19,
|
||||
0x5e757db4b4eab4c9, 0x19a8ce54544d549a, 0xe53b7f93937693ec, 0xaa442f222288220d,
|
||||
0xe9c86364648d6407, 0x12ff2af1f1e3f1db, 0xa2e6cc7373d173bf, 0x5a24821212481290,
|
||||
0x5d807a40401d403a, 0x2810480808200840, 0xe89b95c3c32bc356, 0x7bc5dfecec97ec33,
|
||||
0x90ab4ddbdb4bdb96, 0x1f5fc0a1a1bea161, 0x8307918d8d0e8d1c, 0xc97ac83d3df43df5,
|
||||
0xf1335b97976697cc, 0x0000000000000000, 0xd483f9cfcf1bcf36, 0x87566e2b2bac2b45,
|
||||
0xb3ece17676c57697, 0xb019e68282328264, 0xa9b128d6d67fd6fe, 0x7736c31b1b6c1bd8,
|
||||
0x5b7774b5b5eeb5c1, 0x2943beafaf86af11, 0xdfd41d6a6ab56a77, 0x0da0ea50505d50ba,
|
||||
0x4c8a574545094512, 0x18fb38f3f3ebf3cb, 0xf060ad3030c0309d, 0x74c3c4efef9bef2b,
|
||||
0xc37eda3f3ffc3fe5, 0x1caac75555495592, 0x1059dba2a2b2a279, 0x65c9e9eaea8fea03,
|
||||
0xecca6a656589650f, 0x686903babad2bab9, 0x935e4a2f2fbc2f65, 0xe79d8ec0c027c04e,
|
||||
0x81a160dede5fdebe, 0x6c38fc1c1c701ce0, 0x2ee746fdfdd3fdbb, 0x649a1f4d4d294d52,
|
||||
0xe0397692927292e4, 0xbceafa7575c9758f, 0x1e0c360606180630, 0x9809ae8a8a128a24,
|
||||
0x40794bb2b2f2b2f9, 0x59d185e6e6bfe663, 0x361c7e0e0e380e70, 0x633ee71f1f7c1ff8,
|
||||
0xf7c4556262956237, 0xa3b53ad4d477d4ee, 0x324d81a8a89aa829, 0xf4315296966296c4,
|
||||
0x3aef62f9f9c3f99b, 0xf697a3c5c533c566, 0xb14a102525942535, 0x20b2ab59597959f2,
|
||||
0xae15d084842a8454, 0xa7e4c57272d572b7, 0xdd72ec3939e439d5, 0x6198164c4c2d4c5a,
|
||||
0x3bbc945e5e655eca, 0x85f09f7878fd78e7, 0xd870e53838e038dd, 0x8605988c8c0a8c14,
|
||||
0xb2bf17d1d163d1c6, 0x0b57e4a5a5aea541, 0x4dd9a1e2e2afe243, 0xf8c24e616199612f,
|
||||
0x457b42b3b3f6b3f1, 0xa542342121842115, 0xd625089c9c4a9c94, 0x663cee1e1e781ef0,
|
||||
0x5286614343114322, 0xfc93b1c7c73bc776, 0x2be54ffcfcd7fcb3, 0x1408240404100420,
|
||||
0x08a2e351515951b2, 0xc72f2599995e99bc, 0xc4da226d6da96d4f, 0x391a650d0d340d68,
|
||||
0x35e979fafacffa83, 0x84a369dfdf5bdfb6, 0x9bfca97e7ee57ed7, 0xb44819242490243d,
|
||||
0xd776fe3b3bec3bc5, 0x3d4b9aabab96ab31, 0xd181f0cece1fce3e, 0x5522991111441188,
|
||||
0x8903838f8f068f0c, 0x6b9c044e4e254e4a, 0x517366b7b7e6b7d1, 0x60cbe0ebeb8beb0b,
|
||||
0xcc78c13c3cf03cfd, 0xbf1ffd81813e817c, 0xfe354094946a94d4, 0x0cf31cf7f7fbf7eb,
|
||||
0x676f18b9b9deb9a1, 0x5f268b13134c1398, 0x9c58512c2cb02c7d, 0xb8bb05d3d36bd3d6,
|
||||
0x5cd38ce7e7bbe76b, 0xcbdc396e6ea56e57, 0xf395aac4c437c46e, 0x0f061b03030c0318,
|
||||
0x13acdc565645568a, 0x49885e44440d441a, 0x9efea07f7fe17fdf, 0x374f88a9a99ea921,
|
||||
0x8254672a2aa82a4d, 0x6d6b0abbbbd6bbb1, 0xe29f87c1c123c146, 0x02a6f153535153a2,
|
||||
0x8ba572dcdc57dcae, 0x2716530b0b2c0b58, 0xd327019d9d4e9d9c, 0xc1d82b6c6cad6c47,
|
||||
0xf562a43131c43195, 0xb9e8f37474cd7487, 0x09f115f6f6fff6e3, 0x438c4c464605460a,
|
||||
0x2645a5acac8aac09, 0x970fb589891e893c, 0x4428b414145014a0, 0x42dfbae1e1a3e15b,
|
||||
0x4e2ca616165816b0, 0xd274f73a3ae83acd, 0xd0d2066969b9696f, 0x2d12410909240948,
|
||||
0xade0d77070dd70a7, 0x54716fb6b6e2b6d9, 0xb7bd1ed0d067d0ce, 0x7ec7d6eded93ed3b,
|
||||
0xdb85e2cccc17cc2e, 0x578468424215422a, 0xc22d2c98985a98b4, 0x0e55eda4a4aaa449,
|
||||
0x8850752828a0285d, 0x31b8865c5c6d5cda, 0x3fed6bf8f8c7f893, 0xa411c28686228644,
|
||||
}
|
||||
|
||||
C4 := [256]u64 {
|
||||
0xc07830d818186018, 0x05af462623238c23, 0x7ef991b8c6c63fc6, 0x136fcdfbe8e887e8,
|
||||
0x4ca113cb87872687, 0xa9626d11b8b8dab8, 0x0805020901010401, 0x426e9e0d4f4f214f,
|
||||
0xadee6c9b3636d836, 0x590451ffa6a6a2a6, 0xdebdb90cd2d26fd2, 0xfb06f70ef5f5f3f5,
|
||||
0xef80f2967979f979, 0x5fcede306f6fa16f, 0xfcef3f6d91917e91, 0xaa07a4f852525552,
|
||||
0x27fdc04760609d60, 0x89766535bcbccabc, 0xaccd2b379b9b569b, 0x048c018a8e8e028e,
|
||||
0x71155bd2a3a3b6a3, 0x603c186c0c0c300c, 0xff8af6847b7bf17b, 0xb5e16a803535d435,
|
||||
0xe8693af51d1d741d, 0x5347ddb3e0e0a7e0, 0xf6acb321d7d77bd7, 0x5eed999cc2c22fc2,
|
||||
0x6d965c432e2eb82e, 0x627a96294b4b314b, 0xa321e15dfefedffe, 0x8216aed557574157,
|
||||
0xa8412abd15155415, 0x9fb6eee87777c177, 0xa5eb6e923737dc37, 0x7b56d79ee5e5b3e5,
|
||||
0x8cd923139f9f469f, 0xd317fd23f0f0e7f0, 0x6a7f94204a4a354a, 0x9e95a944dada4fda,
|
||||
0xfa25b0a258587d58, 0x06ca8fcfc9c903c9, 0x558d527c2929a429, 0x5022145a0a0a280a,
|
||||
0xe14f7f50b1b1feb1, 0x691a5dc9a0a0baa0, 0x7fdad6146b6bb16b, 0x5cab17d985852e85,
|
||||
0x8173673cbdbdcebd, 0xd234ba8f5d5d695d, 0x8050209010104010, 0xf303f507f4f4f7f4,
|
||||
0x16c08bddcbcb0bcb, 0xedc67cd33e3ef83e, 0x28110a2d05051405, 0x1fe6ce7867678167,
|
||||
0x7353d597e4e4b7e4, 0x25bb4e0227279c27, 0x3258827341411941, 0x2c9d0ba78b8b168b,
|
||||
0x510153f6a7a7a6a7, 0xcf94fab27d7de97d, 0xdcfb374995956e95, 0x8e9fad56d8d847d8,
|
||||
0x8b30eb70fbfbcbfb, 0x2371c1cdeeee9fee, 0xc791f8bb7c7ced7c, 0x17e3cc7166668566,
|
||||
0xa68ea77bdddd53dd, 0xb84b2eaf17175c17, 0x02468e4547470147, 0x84dc211a9e9e429e,
|
||||
0x1ec589d4caca0fca, 0x75995a582d2db42d, 0x9179632ebfbfc6bf, 0x381b0e3f07071c07,
|
||||
0x012347acadad8ead, 0xea2fb4b05a5a755a, 0x6cb51bef83833683, 0x85ff66b63333cc33,
|
||||
0x3ff2c65c63639163, 0x100a041202020802, 0x39384993aaaa92aa, 0xafa8e2de7171d971,
|
||||
0x0ecf8dc6c8c807c8, 0xc87d32d119196419, 0x7270923b49493949, 0x869aaf5fd9d943d9,
|
||||
0xc31df931f2f2eff2, 0x4b48dba8e3e3abe3, 0xe22ab6b95b5b715b, 0x34920dbc88881a88,
|
||||
0xa4c8293e9a9a529a, 0x2dbe4c0b26269826, 0x8dfa64bf3232c832, 0xe94a7d59b0b0fab0,
|
||||
0x1b6acff2e9e983e9, 0x78331e770f0f3c0f, 0xe6a6b733d5d573d5, 0x74ba1df480803a80,
|
||||
0x997c6127bebec2be, 0x26de87ebcdcd13cd, 0xbde468893434d034, 0x7a75903248483d48,
|
||||
0xab24e354ffffdbff, 0xf78ff48d7a7af57a, 0xf4ea3d6490907a90, 0xc23ebe9d5f5f615f,
|
||||
0x1da0403d20208020, 0x67d5d00f6868bd68, 0xd07234ca1a1a681a, 0x192c41b7aeae82ae,
|
||||
0xc95e757db4b4eab4, 0x9a19a8ce54544d54, 0xece53b7f93937693, 0x0daa442f22228822,
|
||||
0x07e9c86364648d64, 0xdb12ff2af1f1e3f1, 0xbfa2e6cc7373d173, 0x905a248212124812,
|
||||
0x3a5d807a40401d40, 0x4028104808082008, 0x56e89b95c3c32bc3, 0x337bc5dfecec97ec,
|
||||
0x9690ab4ddbdb4bdb, 0x611f5fc0a1a1bea1, 0x1c8307918d8d0e8d, 0xf5c97ac83d3df43d,
|
||||
0xccf1335b97976697, 0x0000000000000000, 0x36d483f9cfcf1bcf, 0x4587566e2b2bac2b,
|
||||
0x97b3ece17676c576, 0x64b019e682823282, 0xfea9b128d6d67fd6, 0xd87736c31b1b6c1b,
|
||||
0xc15b7774b5b5eeb5, 0x112943beafaf86af, 0x77dfd41d6a6ab56a, 0xba0da0ea50505d50,
|
||||
0x124c8a5745450945, 0xcb18fb38f3f3ebf3, 0x9df060ad3030c030, 0x2b74c3c4efef9bef,
|
||||
0xe5c37eda3f3ffc3f, 0x921caac755554955, 0x791059dba2a2b2a2, 0x0365c9e9eaea8fea,
|
||||
0x0fecca6a65658965, 0xb9686903babad2ba, 0x65935e4a2f2fbc2f, 0x4ee79d8ec0c027c0,
|
||||
0xbe81a160dede5fde, 0xe06c38fc1c1c701c, 0xbb2ee746fdfdd3fd, 0x52649a1f4d4d294d,
|
||||
0xe4e0397692927292, 0x8fbceafa7575c975, 0x301e0c3606061806, 0x249809ae8a8a128a,
|
||||
0xf940794bb2b2f2b2, 0x6359d185e6e6bfe6, 0x70361c7e0e0e380e, 0xf8633ee71f1f7c1f,
|
||||
0x37f7c45562629562, 0xeea3b53ad4d477d4, 0x29324d81a8a89aa8, 0xc4f4315296966296,
|
||||
0x9b3aef62f9f9c3f9, 0x66f697a3c5c533c5, 0x35b14a1025259425, 0xf220b2ab59597959,
|
||||
0x54ae15d084842a84, 0xb7a7e4c57272d572, 0xd5dd72ec3939e439, 0x5a6198164c4c2d4c,
|
||||
0xca3bbc945e5e655e, 0xe785f09f7878fd78, 0xddd870e53838e038, 0x148605988c8c0a8c,
|
||||
0xc6b2bf17d1d163d1, 0x410b57e4a5a5aea5, 0x434dd9a1e2e2afe2, 0x2ff8c24e61619961,
|
||||
0xf1457b42b3b3f6b3, 0x15a5423421218421, 0x94d625089c9c4a9c, 0xf0663cee1e1e781e,
|
||||
0x2252866143431143, 0x76fc93b1c7c73bc7, 0xb32be54ffcfcd7fc, 0x2014082404041004,
|
||||
0xb208a2e351515951, 0xbcc72f2599995e99, 0x4fc4da226d6da96d, 0x68391a650d0d340d,
|
||||
0x8335e979fafacffa, 0xb684a369dfdf5bdf, 0xd79bfca97e7ee57e, 0x3db4481924249024,
|
||||
0xc5d776fe3b3bec3b, 0x313d4b9aabab96ab, 0x3ed181f0cece1fce, 0x8855229911114411,
|
||||
0x0c8903838f8f068f, 0x4a6b9c044e4e254e, 0xd1517366b7b7e6b7, 0x0b60cbe0ebeb8beb,
|
||||
0xfdcc78c13c3cf03c, 0x7cbf1ffd81813e81, 0xd4fe354094946a94, 0xeb0cf31cf7f7fbf7,
|
||||
0xa1676f18b9b9deb9, 0x985f268b13134c13, 0x7d9c58512c2cb02c, 0xd6b8bb05d3d36bd3,
|
||||
0x6b5cd38ce7e7bbe7, 0x57cbdc396e6ea56e, 0x6ef395aac4c437c4, 0x180f061b03030c03,
|
||||
0x8a13acdc56564556, 0x1a49885e44440d44, 0xdf9efea07f7fe17f, 0x21374f88a9a99ea9,
|
||||
0x4d8254672a2aa82a, 0xb16d6b0abbbbd6bb, 0x46e29f87c1c123c1, 0xa202a6f153535153,
|
||||
0xae8ba572dcdc57dc, 0x582716530b0b2c0b, 0x9cd327019d9d4e9d, 0x47c1d82b6c6cad6c,
|
||||
0x95f562a43131c431, 0x87b9e8f37474cd74, 0xe309f115f6f6fff6, 0x0a438c4c46460546,
|
||||
0x092645a5acac8aac, 0x3c970fb589891e89, 0xa04428b414145014, 0x5b42dfbae1e1a3e1,
|
||||
0xb04e2ca616165816, 0xcdd274f73a3ae83a, 0x6fd0d2066969b969, 0x482d124109092409,
|
||||
0xa7ade0d77070dd70, 0xd954716fb6b6e2b6, 0xceb7bd1ed0d067d0, 0x3b7ec7d6eded93ed,
|
||||
0x2edb85e2cccc17cc, 0x2a57846842421542, 0xb4c22d2c98985a98, 0x490e55eda4a4aaa4,
|
||||
0x5d8850752828a028, 0xda31b8865c5c6d5c, 0x933fed6bf8f8c7f8, 0x44a411c286862286,
|
||||
}
|
||||
|
||||
C5 := [256]u64 {
|
||||
0x18c07830d8181860, 0x2305af462623238c, 0xc67ef991b8c6c63f, 0xe8136fcdfbe8e887,
|
||||
0x874ca113cb878726, 0xb8a9626d11b8b8da, 0x0108050209010104, 0x4f426e9e0d4f4f21,
|
||||
0x36adee6c9b3636d8, 0xa6590451ffa6a6a2, 0xd2debdb90cd2d26f, 0xf5fb06f70ef5f5f3,
|
||||
0x79ef80f2967979f9, 0x6f5fcede306f6fa1, 0x91fcef3f6d91917e, 0x52aa07a4f8525255,
|
||||
0x6027fdc04760609d, 0xbc89766535bcbcca, 0x9baccd2b379b9b56, 0x8e048c018a8e8e02,
|
||||
0xa371155bd2a3a3b6, 0x0c603c186c0c0c30, 0x7bff8af6847b7bf1, 0x35b5e16a803535d4,
|
||||
0x1de8693af51d1d74, 0xe05347ddb3e0e0a7, 0xd7f6acb321d7d77b, 0xc25eed999cc2c22f,
|
||||
0x2e6d965c432e2eb8, 0x4b627a96294b4b31, 0xfea321e15dfefedf, 0x578216aed5575741,
|
||||
0x15a8412abd151554, 0x779fb6eee87777c1, 0x37a5eb6e923737dc, 0xe57b56d79ee5e5b3,
|
||||
0x9f8cd923139f9f46, 0xf0d317fd23f0f0e7, 0x4a6a7f94204a4a35, 0xda9e95a944dada4f,
|
||||
0x58fa25b0a258587d, 0xc906ca8fcfc9c903, 0x29558d527c2929a4, 0x0a5022145a0a0a28,
|
||||
0xb1e14f7f50b1b1fe, 0xa0691a5dc9a0a0ba, 0x6b7fdad6146b6bb1, 0x855cab17d985852e,
|
||||
0xbd8173673cbdbdce, 0x5dd234ba8f5d5d69, 0x1080502090101040, 0xf4f303f507f4f4f7,
|
||||
0xcb16c08bddcbcb0b, 0x3eedc67cd33e3ef8, 0x0528110a2d050514, 0x671fe6ce78676781,
|
||||
0xe47353d597e4e4b7, 0x2725bb4e0227279c, 0x4132588273414119, 0x8b2c9d0ba78b8b16,
|
||||
0xa7510153f6a7a7a6, 0x7dcf94fab27d7de9, 0x95dcfb374995956e, 0xd88e9fad56d8d847,
|
||||
0xfb8b30eb70fbfbcb, 0xee2371c1cdeeee9f, 0x7cc791f8bb7c7ced, 0x6617e3cc71666685,
|
||||
0xdda68ea77bdddd53, 0x17b84b2eaf17175c, 0x4702468e45474701, 0x9e84dc211a9e9e42,
|
||||
0xca1ec589d4caca0f, 0x2d75995a582d2db4, 0xbf9179632ebfbfc6, 0x07381b0e3f07071c,
|
||||
0xad012347acadad8e, 0x5aea2fb4b05a5a75, 0x836cb51bef838336, 0x3385ff66b63333cc,
|
||||
0x633ff2c65c636391, 0x02100a0412020208, 0xaa39384993aaaa92, 0x71afa8e2de7171d9,
|
||||
0xc80ecf8dc6c8c807, 0x19c87d32d1191964, 0x497270923b494939, 0xd9869aaf5fd9d943,
|
||||
0xf2c31df931f2f2ef, 0xe34b48dba8e3e3ab, 0x5be22ab6b95b5b71, 0x8834920dbc88881a,
|
||||
0x9aa4c8293e9a9a52, 0x262dbe4c0b262698, 0x328dfa64bf3232c8, 0xb0e94a7d59b0b0fa,
|
||||
0xe91b6acff2e9e983, 0x0f78331e770f0f3c, 0xd5e6a6b733d5d573, 0x8074ba1df480803a,
|
||||
0xbe997c6127bebec2, 0xcd26de87ebcdcd13, 0x34bde468893434d0, 0x487a75903248483d,
|
||||
0xffab24e354ffffdb, 0x7af78ff48d7a7af5, 0x90f4ea3d6490907a, 0x5fc23ebe9d5f5f61,
|
||||
0x201da0403d202080, 0x6867d5d00f6868bd, 0x1ad07234ca1a1a68, 0xae192c41b7aeae82,
|
||||
0xb4c95e757db4b4ea, 0x549a19a8ce54544d, 0x93ece53b7f939376, 0x220daa442f222288,
|
||||
0x6407e9c86364648d, 0xf1db12ff2af1f1e3, 0x73bfa2e6cc7373d1, 0x12905a2482121248,
|
||||
0x403a5d807a40401d, 0x0840281048080820, 0xc356e89b95c3c32b, 0xec337bc5dfecec97,
|
||||
0xdb9690ab4ddbdb4b, 0xa1611f5fc0a1a1be, 0x8d1c8307918d8d0e, 0x3df5c97ac83d3df4,
|
||||
0x97ccf1335b979766, 0x0000000000000000, 0xcf36d483f9cfcf1b, 0x2b4587566e2b2bac,
|
||||
0x7697b3ece17676c5, 0x8264b019e6828232, 0xd6fea9b128d6d67f, 0x1bd87736c31b1b6c,
|
||||
0xb5c15b7774b5b5ee, 0xaf112943beafaf86, 0x6a77dfd41d6a6ab5, 0x50ba0da0ea50505d,
|
||||
0x45124c8a57454509, 0xf3cb18fb38f3f3eb, 0x309df060ad3030c0, 0xef2b74c3c4efef9b,
|
||||
0x3fe5c37eda3f3ffc, 0x55921caac7555549, 0xa2791059dba2a2b2, 0xea0365c9e9eaea8f,
|
||||
0x650fecca6a656589, 0xbab9686903babad2, 0x2f65935e4a2f2fbc, 0xc04ee79d8ec0c027,
|
||||
0xdebe81a160dede5f, 0x1ce06c38fc1c1c70, 0xfdbb2ee746fdfdd3, 0x4d52649a1f4d4d29,
|
||||
0x92e4e03976929272, 0x758fbceafa7575c9, 0x06301e0c36060618, 0x8a249809ae8a8a12,
|
||||
0xb2f940794bb2b2f2, 0xe66359d185e6e6bf, 0x0e70361c7e0e0e38, 0x1ff8633ee71f1f7c,
|
||||
0x6237f7c455626295, 0xd4eea3b53ad4d477, 0xa829324d81a8a89a, 0x96c4f43152969662,
|
||||
0xf99b3aef62f9f9c3, 0xc566f697a3c5c533, 0x2535b14a10252594, 0x59f220b2ab595979,
|
||||
0x8454ae15d084842a, 0x72b7a7e4c57272d5, 0x39d5dd72ec3939e4, 0x4c5a6198164c4c2d,
|
||||
0x5eca3bbc945e5e65, 0x78e785f09f7878fd, 0x38ddd870e53838e0, 0x8c148605988c8c0a,
|
||||
0xd1c6b2bf17d1d163, 0xa5410b57e4a5a5ae, 0xe2434dd9a1e2e2af, 0x612ff8c24e616199,
|
||||
0xb3f1457b42b3b3f6, 0x2115a54234212184, 0x9c94d625089c9c4a, 0x1ef0663cee1e1e78,
|
||||
0x4322528661434311, 0xc776fc93b1c7c73b, 0xfcb32be54ffcfcd7, 0x0420140824040410,
|
||||
0x51b208a2e3515159, 0x99bcc72f2599995e, 0x6d4fc4da226d6da9, 0x0d68391a650d0d34,
|
||||
0xfa8335e979fafacf, 0xdfb684a369dfdf5b, 0x7ed79bfca97e7ee5, 0x243db44819242490,
|
||||
0x3bc5d776fe3b3bec, 0xab313d4b9aabab96, 0xce3ed181f0cece1f, 0x1188552299111144,
|
||||
0x8f0c8903838f8f06, 0x4e4a6b9c044e4e25, 0xb7d1517366b7b7e6, 0xeb0b60cbe0ebeb8b,
|
||||
0x3cfdcc78c13c3cf0, 0x817cbf1ffd81813e, 0x94d4fe354094946a, 0xf7eb0cf31cf7f7fb,
|
||||
0xb9a1676f18b9b9de, 0x13985f268b13134c, 0x2c7d9c58512c2cb0, 0xd3d6b8bb05d3d36b,
|
||||
0xe76b5cd38ce7e7bb, 0x6e57cbdc396e6ea5, 0xc46ef395aac4c437, 0x03180f061b03030c,
|
||||
0x568a13acdc565645, 0x441a49885e44440d, 0x7fdf9efea07f7fe1, 0xa921374f88a9a99e,
|
||||
0x2a4d8254672a2aa8, 0xbbb16d6b0abbbbd6, 0xc146e29f87c1c123, 0x53a202a6f1535351,
|
||||
0xdcae8ba572dcdc57, 0x0b582716530b0b2c, 0x9d9cd327019d9d4e, 0x6c47c1d82b6c6cad,
|
||||
0x3195f562a43131c4, 0x7487b9e8f37474cd, 0xf6e309f115f6f6ff, 0x460a438c4c464605,
|
||||
0xac092645a5acac8a, 0x893c970fb589891e, 0x14a04428b4141450, 0xe15b42dfbae1e1a3,
|
||||
0x16b04e2ca6161658, 0x3acdd274f73a3ae8, 0x696fd0d2066969b9, 0x09482d1241090924,
|
||||
0x70a7ade0d77070dd, 0xb6d954716fb6b6e2, 0xd0ceb7bd1ed0d067, 0xed3b7ec7d6eded93,
|
||||
0xcc2edb85e2cccc17, 0x422a578468424215, 0x98b4c22d2c98985a, 0xa4490e55eda4a4aa,
|
||||
0x285d8850752828a0, 0x5cda31b8865c5c6d, 0xf8933fed6bf8f8c7, 0x8644a411c2868622,
|
||||
}
|
||||
|
||||
C6 := [256]u64 {
|
||||
0x6018c07830d81818, 0x8c2305af46262323, 0x3fc67ef991b8c6c6, 0x87e8136fcdfbe8e8,
|
||||
0x26874ca113cb8787, 0xdab8a9626d11b8b8, 0x0401080502090101, 0x214f426e9e0d4f4f,
|
||||
0xd836adee6c9b3636, 0xa2a6590451ffa6a6, 0x6fd2debdb90cd2d2, 0xf3f5fb06f70ef5f5,
|
||||
0xf979ef80f2967979, 0xa16f5fcede306f6f, 0x7e91fcef3f6d9191, 0x5552aa07a4f85252,
|
||||
0x9d6027fdc0476060, 0xcabc89766535bcbc, 0x569baccd2b379b9b, 0x028e048c018a8e8e,
|
||||
0xb6a371155bd2a3a3, 0x300c603c186c0c0c, 0xf17bff8af6847b7b, 0xd435b5e16a803535,
|
||||
0x741de8693af51d1d, 0xa7e05347ddb3e0e0, 0x7bd7f6acb321d7d7, 0x2fc25eed999cc2c2,
|
||||
0xb82e6d965c432e2e, 0x314b627a96294b4b, 0xdffea321e15dfefe, 0x41578216aed55757,
|
||||
0x5415a8412abd1515, 0xc1779fb6eee87777, 0xdc37a5eb6e923737, 0xb3e57b56d79ee5e5,
|
||||
0x469f8cd923139f9f, 0xe7f0d317fd23f0f0, 0x354a6a7f94204a4a, 0x4fda9e95a944dada,
|
||||
0x7d58fa25b0a25858, 0x03c906ca8fcfc9c9, 0xa429558d527c2929, 0x280a5022145a0a0a,
|
||||
0xfeb1e14f7f50b1b1, 0xbaa0691a5dc9a0a0, 0xb16b7fdad6146b6b, 0x2e855cab17d98585,
|
||||
0xcebd8173673cbdbd, 0x695dd234ba8f5d5d, 0x4010805020901010, 0xf7f4f303f507f4f4,
|
||||
0x0bcb16c08bddcbcb, 0xf83eedc67cd33e3e, 0x140528110a2d0505, 0x81671fe6ce786767,
|
||||
0xb7e47353d597e4e4, 0x9c2725bb4e022727, 0x1941325882734141, 0x168b2c9d0ba78b8b,
|
||||
0xa6a7510153f6a7a7, 0xe97dcf94fab27d7d, 0x6e95dcfb37499595, 0x47d88e9fad56d8d8,
|
||||
0xcbfb8b30eb70fbfb, 0x9fee2371c1cdeeee, 0xed7cc791f8bb7c7c, 0x856617e3cc716666,
|
||||
0x53dda68ea77bdddd, 0x5c17b84b2eaf1717, 0x014702468e454747, 0x429e84dc211a9e9e,
|
||||
0x0fca1ec589d4caca, 0xb42d75995a582d2d, 0xc6bf9179632ebfbf, 0x1c07381b0e3f0707,
|
||||
0x8ead012347acadad, 0x755aea2fb4b05a5a, 0x36836cb51bef8383, 0xcc3385ff66b63333,
|
||||
0x91633ff2c65c6363, 0x0802100a04120202, 0x92aa39384993aaaa, 0xd971afa8e2de7171,
|
||||
0x07c80ecf8dc6c8c8, 0x6419c87d32d11919, 0x39497270923b4949, 0x43d9869aaf5fd9d9,
|
||||
0xeff2c31df931f2f2, 0xabe34b48dba8e3e3, 0x715be22ab6b95b5b, 0x1a8834920dbc8888,
|
||||
0x529aa4c8293e9a9a, 0x98262dbe4c0b2626, 0xc8328dfa64bf3232, 0xfab0e94a7d59b0b0,
|
||||
0x83e91b6acff2e9e9, 0x3c0f78331e770f0f, 0x73d5e6a6b733d5d5, 0x3a8074ba1df48080,
|
||||
0xc2be997c6127bebe, 0x13cd26de87ebcdcd, 0xd034bde468893434, 0x3d487a7590324848,
|
||||
0xdbffab24e354ffff, 0xf57af78ff48d7a7a, 0x7a90f4ea3d649090, 0x615fc23ebe9d5f5f,
|
||||
0x80201da0403d2020, 0xbd6867d5d00f6868, 0x681ad07234ca1a1a, 0x82ae192c41b7aeae,
|
||||
0xeab4c95e757db4b4, 0x4d549a19a8ce5454, 0x7693ece53b7f9393, 0x88220daa442f2222,
|
||||
0x8d6407e9c8636464, 0xe3f1db12ff2af1f1, 0xd173bfa2e6cc7373, 0x4812905a24821212,
|
||||
0x1d403a5d807a4040, 0x2008402810480808, 0x2bc356e89b95c3c3, 0x97ec337bc5dfecec,
|
||||
0x4bdb9690ab4ddbdb, 0xbea1611f5fc0a1a1, 0x0e8d1c8307918d8d, 0xf43df5c97ac83d3d,
|
||||
0x6697ccf1335b9797, 0x0000000000000000, 0x1bcf36d483f9cfcf, 0xac2b4587566e2b2b,
|
||||
0xc57697b3ece17676, 0x328264b019e68282, 0x7fd6fea9b128d6d6, 0x6c1bd87736c31b1b,
|
||||
0xeeb5c15b7774b5b5, 0x86af112943beafaf, 0xb56a77dfd41d6a6a, 0x5d50ba0da0ea5050,
|
||||
0x0945124c8a574545, 0xebf3cb18fb38f3f3, 0xc0309df060ad3030, 0x9bef2b74c3c4efef,
|
||||
0xfc3fe5c37eda3f3f, 0x4955921caac75555, 0xb2a2791059dba2a2, 0x8fea0365c9e9eaea,
|
||||
0x89650fecca6a6565, 0xd2bab9686903baba, 0xbc2f65935e4a2f2f, 0x27c04ee79d8ec0c0,
|
||||
0x5fdebe81a160dede, 0x701ce06c38fc1c1c, 0xd3fdbb2ee746fdfd, 0x294d52649a1f4d4d,
|
||||
0x7292e4e039769292, 0xc9758fbceafa7575, 0x1806301e0c360606, 0x128a249809ae8a8a,
|
||||
0xf2b2f940794bb2b2, 0xbfe66359d185e6e6, 0x380e70361c7e0e0e, 0x7c1ff8633ee71f1f,
|
||||
0x956237f7c4556262, 0x77d4eea3b53ad4d4, 0x9aa829324d81a8a8, 0x6296c4f431529696,
|
||||
0xc3f99b3aef62f9f9, 0x33c566f697a3c5c5, 0x942535b14a102525, 0x7959f220b2ab5959,
|
||||
0x2a8454ae15d08484, 0xd572b7a7e4c57272, 0xe439d5dd72ec3939, 0x2d4c5a6198164c4c,
|
||||
0x655eca3bbc945e5e, 0xfd78e785f09f7878, 0xe038ddd870e53838, 0x0a8c148605988c8c,
|
||||
0x63d1c6b2bf17d1d1, 0xaea5410b57e4a5a5, 0xafe2434dd9a1e2e2, 0x99612ff8c24e6161,
|
||||
0xf6b3f1457b42b3b3, 0x842115a542342121, 0x4a9c94d625089c9c, 0x781ef0663cee1e1e,
|
||||
0x1143225286614343, 0x3bc776fc93b1c7c7, 0xd7fcb32be54ffcfc, 0x1004201408240404,
|
||||
0x5951b208a2e35151, 0x5e99bcc72f259999, 0xa96d4fc4da226d6d, 0x340d68391a650d0d,
|
||||
0xcffa8335e979fafa, 0x5bdfb684a369dfdf, 0xe57ed79bfca97e7e, 0x90243db448192424,
|
||||
0xec3bc5d776fe3b3b, 0x96ab313d4b9aabab, 0x1fce3ed181f0cece, 0x4411885522991111,
|
||||
0x068f0c8903838f8f, 0x254e4a6b9c044e4e, 0xe6b7d1517366b7b7, 0x8beb0b60cbe0ebeb,
|
||||
0xf03cfdcc78c13c3c, 0x3e817cbf1ffd8181, 0x6a94d4fe35409494, 0xfbf7eb0cf31cf7f7,
|
||||
0xdeb9a1676f18b9b9, 0x4c13985f268b1313, 0xb02c7d9c58512c2c, 0x6bd3d6b8bb05d3d3,
|
||||
0xbbe76b5cd38ce7e7, 0xa56e57cbdc396e6e, 0x37c46ef395aac4c4, 0x0c03180f061b0303,
|
||||
0x45568a13acdc5656, 0x0d441a49885e4444, 0xe17fdf9efea07f7f, 0x9ea921374f88a9a9,
|
||||
0xa82a4d8254672a2a, 0xd6bbb16d6b0abbbb, 0x23c146e29f87c1c1, 0x5153a202a6f15353,
|
||||
0x57dcae8ba572dcdc, 0x2c0b582716530b0b, 0x4e9d9cd327019d9d, 0xad6c47c1d82b6c6c,
|
||||
0xc43195f562a43131, 0xcd7487b9e8f37474, 0xfff6e309f115f6f6, 0x05460a438c4c4646,
|
||||
0x8aac092645a5acac, 0x1e893c970fb58989, 0x5014a04428b41414, 0xa3e15b42dfbae1e1,
|
||||
0x5816b04e2ca61616, 0xe83acdd274f73a3a, 0xb9696fd0d2066969, 0x2409482d12410909,
|
||||
0xdd70a7ade0d77070, 0xe2b6d954716fb6b6, 0x67d0ceb7bd1ed0d0, 0x93ed3b7ec7d6eded,
|
||||
0x17cc2edb85e2cccc, 0x15422a5784684242, 0x5a98b4c22d2c9898, 0xaaa4490e55eda4a4,
|
||||
0xa0285d8850752828, 0x6d5cda31b8865c5c, 0xc7f8933fed6bf8f8, 0x228644a411c28686,
|
||||
}
|
||||
|
||||
C7 := [256]u64 {
|
||||
0x186018c07830d818, 0x238c2305af462623, 0xc63fc67ef991b8c6, 0xe887e8136fcdfbe8,
|
||||
0x8726874ca113cb87, 0xb8dab8a9626d11b8, 0x0104010805020901, 0x4f214f426e9e0d4f,
|
||||
0x36d836adee6c9b36, 0xa6a2a6590451ffa6, 0xd26fd2debdb90cd2, 0xf5f3f5fb06f70ef5,
|
||||
0x79f979ef80f29679, 0x6fa16f5fcede306f, 0x917e91fcef3f6d91, 0x525552aa07a4f852,
|
||||
0x609d6027fdc04760, 0xbccabc89766535bc, 0x9b569baccd2b379b, 0x8e028e048c018a8e,
|
||||
0xa3b6a371155bd2a3, 0x0c300c603c186c0c, 0x7bf17bff8af6847b, 0x35d435b5e16a8035,
|
||||
0x1d741de8693af51d, 0xe0a7e05347ddb3e0, 0xd77bd7f6acb321d7, 0xc22fc25eed999cc2,
|
||||
0x2eb82e6d965c432e, 0x4b314b627a96294b, 0xfedffea321e15dfe, 0x5741578216aed557,
|
||||
0x155415a8412abd15, 0x77c1779fb6eee877, 0x37dc37a5eb6e9237, 0xe5b3e57b56d79ee5,
|
||||
0x9f469f8cd923139f, 0xf0e7f0d317fd23f0, 0x4a354a6a7f94204a, 0xda4fda9e95a944da,
|
||||
0x587d58fa25b0a258, 0xc903c906ca8fcfc9, 0x29a429558d527c29, 0x0a280a5022145a0a,
|
||||
0xb1feb1e14f7f50b1, 0xa0baa0691a5dc9a0, 0x6bb16b7fdad6146b, 0x852e855cab17d985,
|
||||
0xbdcebd8173673cbd, 0x5d695dd234ba8f5d, 0x1040108050209010, 0xf4f7f4f303f507f4,
|
||||
0xcb0bcb16c08bddcb, 0x3ef83eedc67cd33e, 0x05140528110a2d05, 0x6781671fe6ce7867,
|
||||
0xe4b7e47353d597e4, 0x279c2725bb4e0227, 0x4119413258827341, 0x8b168b2c9d0ba78b,
|
||||
0xa7a6a7510153f6a7, 0x7de97dcf94fab27d, 0x956e95dcfb374995, 0xd847d88e9fad56d8,
|
||||
0xfbcbfb8b30eb70fb, 0xee9fee2371c1cdee, 0x7ced7cc791f8bb7c, 0x66856617e3cc7166,
|
||||
0xdd53dda68ea77bdd, 0x175c17b84b2eaf17, 0x47014702468e4547, 0x9e429e84dc211a9e,
|
||||
0xca0fca1ec589d4ca, 0x2db42d75995a582d, 0xbfc6bf9179632ebf, 0x071c07381b0e3f07,
|
||||
0xad8ead012347acad, 0x5a755aea2fb4b05a, 0x8336836cb51bef83, 0x33cc3385ff66b633,
|
||||
0x6391633ff2c65c63, 0x020802100a041202, 0xaa92aa39384993aa, 0x71d971afa8e2de71,
|
||||
0xc807c80ecf8dc6c8, 0x196419c87d32d119, 0x4939497270923b49, 0xd943d9869aaf5fd9,
|
||||
0xf2eff2c31df931f2, 0xe3abe34b48dba8e3, 0x5b715be22ab6b95b, 0x881a8834920dbc88,
|
||||
0x9a529aa4c8293e9a, 0x2698262dbe4c0b26, 0x32c8328dfa64bf32, 0xb0fab0e94a7d59b0,
|
||||
0xe983e91b6acff2e9, 0x0f3c0f78331e770f, 0xd573d5e6a6b733d5, 0x803a8074ba1df480,
|
||||
0xbec2be997c6127be, 0xcd13cd26de87ebcd, 0x34d034bde4688934, 0x483d487a75903248,
|
||||
0xffdbffab24e354ff, 0x7af57af78ff48d7a, 0x907a90f4ea3d6490, 0x5f615fc23ebe9d5f,
|
||||
0x2080201da0403d20, 0x68bd6867d5d00f68, 0x1a681ad07234ca1a, 0xae82ae192c41b7ae,
|
||||
0xb4eab4c95e757db4, 0x544d549a19a8ce54, 0x937693ece53b7f93, 0x2288220daa442f22,
|
||||
0x648d6407e9c86364, 0xf1e3f1db12ff2af1, 0x73d173bfa2e6cc73, 0x124812905a248212,
|
||||
0x401d403a5d807a40, 0x0820084028104808, 0xc32bc356e89b95c3, 0xec97ec337bc5dfec,
|
||||
0xdb4bdb9690ab4ddb, 0xa1bea1611f5fc0a1, 0x8d0e8d1c8307918d, 0x3df43df5c97ac83d,
|
||||
0x976697ccf1335b97, 0x0000000000000000, 0xcf1bcf36d483f9cf, 0x2bac2b4587566e2b,
|
||||
0x76c57697b3ece176, 0x82328264b019e682, 0xd67fd6fea9b128d6, 0x1b6c1bd87736c31b,
|
||||
0xb5eeb5c15b7774b5, 0xaf86af112943beaf, 0x6ab56a77dfd41d6a, 0x505d50ba0da0ea50,
|
||||
0x450945124c8a5745, 0xf3ebf3cb18fb38f3, 0x30c0309df060ad30, 0xef9bef2b74c3c4ef,
|
||||
0x3ffc3fe5c37eda3f, 0x554955921caac755, 0xa2b2a2791059dba2, 0xea8fea0365c9e9ea,
|
||||
0x6589650fecca6a65, 0xbad2bab9686903ba, 0x2fbc2f65935e4a2f, 0xc027c04ee79d8ec0,
|
||||
0xde5fdebe81a160de, 0x1c701ce06c38fc1c, 0xfdd3fdbb2ee746fd, 0x4d294d52649a1f4d,
|
||||
0x927292e4e0397692, 0x75c9758fbceafa75, 0x061806301e0c3606, 0x8a128a249809ae8a,
|
||||
0xb2f2b2f940794bb2, 0xe6bfe66359d185e6, 0x0e380e70361c7e0e, 0x1f7c1ff8633ee71f,
|
||||
0x62956237f7c45562, 0xd477d4eea3b53ad4, 0xa89aa829324d81a8, 0x966296c4f4315296,
|
||||
0xf9c3f99b3aef62f9, 0xc533c566f697a3c5, 0x25942535b14a1025, 0x597959f220b2ab59,
|
||||
0x842a8454ae15d084, 0x72d572b7a7e4c572, 0x39e439d5dd72ec39, 0x4c2d4c5a6198164c,
|
||||
0x5e655eca3bbc945e, 0x78fd78e785f09f78, 0x38e038ddd870e538, 0x8c0a8c148605988c,
|
||||
0xd163d1c6b2bf17d1, 0xa5aea5410b57e4a5, 0xe2afe2434dd9a1e2, 0x6199612ff8c24e61,
|
||||
0xb3f6b3f1457b42b3, 0x21842115a5423421, 0x9c4a9c94d625089c, 0x1e781ef0663cee1e,
|
||||
0x4311432252866143, 0xc73bc776fc93b1c7, 0xfcd7fcb32be54ffc, 0x0410042014082404,
|
||||
0x515951b208a2e351, 0x995e99bcc72f2599, 0x6da96d4fc4da226d, 0x0d340d68391a650d,
|
||||
0xfacffa8335e979fa, 0xdf5bdfb684a369df, 0x7ee57ed79bfca97e, 0x2490243db4481924,
|
||||
0x3bec3bc5d776fe3b, 0xab96ab313d4b9aab, 0xce1fce3ed181f0ce, 0x1144118855229911,
|
||||
0x8f068f0c8903838f, 0x4e254e4a6b9c044e, 0xb7e6b7d1517366b7, 0xeb8beb0b60cbe0eb,
|
||||
0x3cf03cfdcc78c13c, 0x813e817cbf1ffd81, 0x946a94d4fe354094, 0xf7fbf7eb0cf31cf7,
|
||||
0xb9deb9a1676f18b9, 0x134c13985f268b13, 0x2cb02c7d9c58512c, 0xd36bd3d6b8bb05d3,
|
||||
0xe7bbe76b5cd38ce7, 0x6ea56e57cbdc396e, 0xc437c46ef395aac4, 0x030c03180f061b03,
|
||||
0x5645568a13acdc56, 0x440d441a49885e44, 0x7fe17fdf9efea07f, 0xa99ea921374f88a9,
|
||||
0x2aa82a4d8254672a, 0xbbd6bbb16d6b0abb, 0xc123c146e29f87c1, 0x535153a202a6f153,
|
||||
0xdc57dcae8ba572dc, 0x0b2c0b582716530b, 0x9d4e9d9cd327019d, 0x6cad6c47c1d82b6c,
|
||||
0x31c43195f562a431, 0x74cd7487b9e8f374, 0xf6fff6e309f115f6, 0x4605460a438c4c46,
|
||||
0xac8aac092645a5ac, 0x891e893c970fb589, 0x145014a04428b414, 0xe1a3e15b42dfbae1,
|
||||
0x165816b04e2ca616, 0x3ae83acdd274f73a, 0x69b9696fd0d20669, 0x092409482d124109,
|
||||
0x70dd70a7ade0d770, 0xb6e2b6d954716fb6, 0xd067d0ceb7bd1ed0, 0xed93ed3b7ec7d6ed,
|
||||
0xcc17cc2edb85e2cc, 0x4215422a57846842, 0x985a98b4c22d2c98, 0xa4aaa4490e55eda4,
|
||||
0x28a0285d88507528, 0x5c6d5cda31b8865c, 0xf8c7f8933fed6bf8, 0x86228644a411c286,
|
||||
}
|
||||
|
||||
RC := [ROUNDS + 1]u64 {
|
||||
0x0000000000000000,
|
||||
0x1823c6e887b8014f,
|
||||
0x36a6d2f5796f9152,
|
||||
0x60bc9b8ea30c7b35,
|
||||
0x1de0d7c22e4bfe57,
|
||||
0x157737e59ff04ada,
|
||||
0x58c9290ab1a06b85,
|
||||
0xbd5d10f4cb3e0567,
|
||||
0xe427418ba77d95d8,
|
||||
0xfbee7c66dd17479e,
|
||||
0xca2dbf07ad5a8333,
|
||||
}
|
||||
|
||||
transform :: proc (ctx: ^Whirlpool_Context) {
|
||||
K, block, state, L: [8]u64
|
||||
|
||||
for i := 0; i < 8; i += 1 {block[i] = util.U64_BE(ctx.buffer[8 * i:])}
|
||||
|
||||
for i := 0; i < 8; i += 1 {
|
||||
K[i] = ctx.hash[i]
|
||||
state[i] = block[i] ~ K[i]
|
||||
}
|
||||
|
||||
for r := 1; r <= ROUNDS; r += 1 {
|
||||
for i := 0; i < 8; i += 1 {
|
||||
L[i] = C0[byte(K[i % 8] >> 56)] ~
|
||||
C1[byte(K[(i + 7) % 8] >> 48)] ~
|
||||
C2[byte(K[(i + 6) % 8] >> 40)] ~
|
||||
C3[byte(K[(i + 5) % 8] >> 32)] ~
|
||||
C4[byte(K[(i + 4) % 8] >> 24)] ~
|
||||
C5[byte(K[(i + 3) % 8] >> 16)] ~
|
||||
C6[byte(K[(i + 2) % 8] >> 8)] ~
|
||||
C7[byte(K[(i + 1) % 8])]
|
||||
}
|
||||
L[0] ~= RC[r]
|
||||
|
||||
for i := 0; i < 8; i += 1 {K[i] = L[i]}
|
||||
|
||||
for i := 0; i < 8; i += 1 {
|
||||
L[i] = C0[byte(state[i % 8] >> 56)] ~
|
||||
C1[byte(state[(i + 7) % 8] >> 48)] ~
|
||||
C2[byte(state[(i + 6) % 8] >> 40)] ~
|
||||
C3[byte(state[(i + 5) % 8] >> 32)] ~
|
||||
C4[byte(state[(i + 4) % 8] >> 24)] ~
|
||||
C5[byte(state[(i + 3) % 8] >> 16)] ~
|
||||
C6[byte(state[(i + 2) % 8] >> 8)] ~
|
||||
C7[byte(state[(i + 1) % 8])] ~
|
||||
K[i % 8]
|
||||
}
|
||||
for i := 0; i < 8; i += 1 {state[i] = L[i]}
|
||||
}
|
||||
for i := 0; i < 8; i += 1 {ctx.hash[i] ~= state[i] ~ block[i]}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package x25519
|
||||
|
||||
import field "core:crypto/_fiat/field_curve25519"
|
||||
import "core:mem"
|
||||
|
||||
SCALAR_SIZE :: 32
|
||||
POINT_SIZE :: 32
|
||||
|
||||
_BASE_POINT: [32]byte = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
_scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 {
|
||||
if i < 0 {
|
||||
return 0
|
||||
}
|
||||
return (s[i>>3] >> uint(i&7)) & 1
|
||||
}
|
||||
|
||||
_scalarmult :: proc (out, scalar, point: ^[32]byte) {
|
||||
// Montgomery pseduo-multiplication taken from Monocypher.
|
||||
|
||||
// computes the scalar product
|
||||
x1: field.Tight_Field_Element = ---
|
||||
field.fe_from_bytes(&x1, point)
|
||||
|
||||
// computes the actual scalar product (the result is in x2 and z2)
|
||||
x2, x3, z2, z3: field.Tight_Field_Element = ---, ---, ---, ---
|
||||
t0, t1: field.Loose_Field_Element = ---, ---
|
||||
|
||||
// Montgomery ladder
|
||||
// In projective coordinates, to avoid divisions: x = X / Z
|
||||
// We don't care about the y coordinate, it's only 1 bit of information
|
||||
field.fe_one(&x2) // "zero" point
|
||||
field.fe_zero(&z2)
|
||||
field.fe_set(&x3, &x1) // "one" point
|
||||
field.fe_one(&z3)
|
||||
|
||||
swap: int
|
||||
for pos := 255-1; pos >= 0; pos = pos - 1 {
|
||||
// constant time conditional swap before ladder step
|
||||
b := int(_scalar_bit(scalar, pos))
|
||||
swap ~= b // xor trick avoids swapping at the end of the loop
|
||||
field.fe_cond_swap(&x2, &x3, swap)
|
||||
field.fe_cond_swap(&z2, &z3, swap)
|
||||
swap = b // anticipates one last swap after the loop
|
||||
|
||||
// Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3)
|
||||
// with differential addition
|
||||
//
|
||||
// Note: This deliberately omits reductions after add/sub operations
|
||||
// if the result is only ever used as the input to a mul/square since
|
||||
// the implementations of those can deal with non-reduced inputs.
|
||||
//
|
||||
// fe_tighten_cast is only used to store a fully reduced
|
||||
// output in a Loose_Field_Element, or to provide such a
|
||||
// Loose_Field_Element as a Tight_Field_Element argument.
|
||||
field.fe_sub(&t0, &x3, &z3)
|
||||
field.fe_sub(&t1, &x2, &z2)
|
||||
field.fe_add(field.fe_relax_cast(&x2), &x2, &z2) // x2 - unreduced
|
||||
field.fe_add(field.fe_relax_cast(&z2), &x3, &z3) // z2 - unreduced
|
||||
field.fe_carry_mul(&z3, &t0, field.fe_relax_cast(&x2))
|
||||
field.fe_carry_mul(&z2, field.fe_relax_cast(&z2), &t1) // z2 - reduced
|
||||
field.fe_carry_square(field.fe_tighten_cast(&t0), &t1) // t0 - reduced
|
||||
field.fe_carry_square(field.fe_tighten_cast(&t1), field.fe_relax_cast(&x2)) // t1 - reduced
|
||||
field.fe_add(field.fe_relax_cast(&x3), &z3, &z2) // x3 - unreduced
|
||||
field.fe_sub(field.fe_relax_cast(&z2), &z3, &z2) // z2 - unreduced
|
||||
field.fe_carry_mul(&x2, &t1, &t0) // x2 - reduced
|
||||
field.fe_sub(&t1, field.fe_tighten_cast(&t1), field.fe_tighten_cast(&t0)) // safe - t1/t0 is reduced
|
||||
field.fe_carry_square(&z2, field.fe_relax_cast(&z2)) // z2 - reduced
|
||||
field.fe_carry_scmul_121666(&z3, &t1)
|
||||
field.fe_carry_square(&x3, field.fe_relax_cast(&x3)) // x3 - reduced
|
||||
field.fe_add(&t0, field.fe_tighten_cast(&t0), &z3) // safe - t0 is reduced
|
||||
field.fe_carry_mul(&z3, field.fe_relax_cast(&x1), field.fe_relax_cast(&z2))
|
||||
field.fe_carry_mul(&z2, &t1, &t0)
|
||||
}
|
||||
// last swap is necessary to compensate for the xor trick
|
||||
// Note: after this swap, P3 == P2 + P1.
|
||||
field.fe_cond_swap(&x2, &x3, swap)
|
||||
field.fe_cond_swap(&z2, &z3, swap)
|
||||
|
||||
// normalises the coordinates: x == X / Z
|
||||
field.fe_carry_inv(&z2, field.fe_relax_cast(&z2))
|
||||
field.fe_carry_mul(&x2, field.fe_relax_cast(&x2), field.fe_relax_cast(&z2))
|
||||
field.fe_to_bytes(out, &x2)
|
||||
|
||||
mem.zero_explicit(&x1, size_of(x1))
|
||||
mem.zero_explicit(&x2, size_of(x2))
|
||||
mem.zero_explicit(&x3, size_of(x3))
|
||||
mem.zero_explicit(&z2, size_of(z2))
|
||||
mem.zero_explicit(&z3, size_of(z3))
|
||||
mem.zero_explicit(&t0, size_of(t0))
|
||||
mem.zero_explicit(&t1, size_of(t1))
|
||||
}
|
||||
|
||||
scalarmult :: proc (dst, scalar, point: []byte) {
|
||||
if len(scalar) != SCALAR_SIZE {
|
||||
panic("crypto/x25519: invalid scalar size")
|
||||
}
|
||||
if len(point) != POINT_SIZE {
|
||||
panic("crypto/x25519: invalid point size")
|
||||
}
|
||||
if len(dst) != POINT_SIZE {
|
||||
panic("crypto/x25519: invalid destination point size")
|
||||
}
|
||||
|
||||
// "clamp" the scalar
|
||||
e: [32]byte = ---
|
||||
copy_slice(e[:], scalar)
|
||||
e[0] &= 248
|
||||
e[31] &= 127
|
||||
e[31] |= 64
|
||||
|
||||
p: [32]byte = ---
|
||||
copy_slice(p[:], point)
|
||||
|
||||
d: [32]byte = ---
|
||||
_scalarmult(&d, &e, &p)
|
||||
copy_slice(dst, d[:])
|
||||
|
||||
mem.zero_explicit(&e, size_of(e))
|
||||
mem.zero_explicit(&d, size_of(d))
|
||||
}
|
||||
|
||||
scalarmult_basepoint :: proc (dst, scalar: []byte) {
|
||||
// TODO/perf: Switch to using a precomputed table.
|
||||
scalarmult(dst, scalar, _BASE_POINT[:])
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user