mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 03:01:38 -07:00
Compare commits
2819 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31b1aef44e | |||
| a8c09d77ff | |||
| 2e1b2dc3ba | |||
| 65333181fc | |||
| 65afe6f70d | |||
| 291a064725 | |||
| c5c46c5073 | |||
| abe896a7be | |||
| f00df0afe9 | |||
| 35f21abc7b | |||
| b1977dfa4b | |||
| e23eba0914 | |||
| 4b245e2d83 | |||
| f169d8c396 | |||
| 4aa8834d39 | |||
| f79efd43e4 | |||
| 5a661dc67b | |||
| e8e3501443 | |||
| 9f96382558 | |||
| 82088e4a75 | |||
| b12bfe407d | |||
| 1db5e1250f | |||
| cabaac5a68 | |||
| 2bb5c4cafc | |||
| bfff322eb9 | |||
| dd60802db4 | |||
| 6db42cfaec | |||
| 21f5b41150 | |||
| 1f007a46ee | |||
| 4fa4feb669 | |||
| 5fd3fc4c7c | |||
| ee2d3e00fd | |||
| 6f65ed6cc8 | |||
| 70525a12ca | |||
| 914950592c | |||
| 3c021f9c52 | |||
| 9ea88f1353 | |||
| 4d89249caf | |||
| ff0e976ff3 | |||
| 0df1645422 | |||
| bb6d73953c | |||
| c9c14bab8a | |||
| 7c6117bb8f | |||
| ae40946198 | |||
| 8063569cdd | |||
| dab72d5615 | |||
| 89493b70a9 | |||
| c12eb3ec93 | |||
| 7343ed0cac | |||
| 3102abf1aa | |||
| 490c8daedd | |||
| e78ee90ac2 | |||
| f809788f75 | |||
| 0888c69b57 | |||
| ab39644156 | |||
| 4c1a9d2b3f | |||
| f6308ab5b9 | |||
| 3baf8d92c3 | |||
| 34065865a0 | |||
| 3d90e580c5 | |||
| f635d3d8af | |||
| 29f1b79d70 | |||
| 955be66f1a | |||
| a0e6ae6f33 | |||
| 08d032859f | |||
| 4af77aeff6 | |||
| 6749639eb1 | |||
| 8a56bb3b5f | |||
| 37e79f9cca | |||
| a4c64002c5 | |||
| 63b6e8216c | |||
| 3e7b5670fb | |||
| e2e18324ed | |||
| 924039c01b | |||
| 2af2a035dc | |||
| f97ccca514 | |||
| 25e9255157 | |||
| 2e64866838 | |||
| d9fab5e824 | |||
| 0424404140 | |||
| db89c2ccd0 | |||
| 0c97f6aa4e | |||
| af78ad2a87 | |||
| 9cc5cd9d40 | |||
| 59950bcad6 | |||
| 4587a55486 | |||
| 7640fb0483 | |||
| b8f9deb3d8 | |||
| 92aad90c6b | |||
| 506adfb105 | |||
| e819eebc63 | |||
| 841e73fcd5 | |||
| aa821991b8 | |||
| b71afdc3ee | |||
| bc139ba6c6 | |||
| 8af6da5de1 | |||
| 0b86038482 | |||
| 8d943f5902 | |||
| 32b27c690d | |||
| 3494a6dcd8 | |||
| 235fec23af | |||
| 97b066f112 | |||
| a99c0b3e4a | |||
| 2a6fb3a387 | |||
| 65204f13a8 | |||
| 8438d66e6b | |||
| 44c8da7bf2 | |||
| 41fdcfeecf | |||
| 70ba4b5321 | |||
| 71da3ef925 | |||
| 582bd760b7 | |||
| e86bb3a795 | |||
| e3a836f93c | |||
| 31b42a53fc | |||
| b71d3c739a | |||
| a162b51588 | |||
| 7c1119f217 | |||
| b0397581db | |||
| c7dc1220b3 | |||
| d16acdc89c | |||
| 1279ebe948 | |||
| aa5a95a4d1 | |||
| fa1cb28c8f | |||
| 3902273d68 | |||
| 811132ccbd | |||
| 391b3090c9 | |||
| d50380709d | |||
| 14a46c6d5e | |||
| b4e3da84c5 | |||
| 9d627e453a | |||
| d6e0e5d3f6 | |||
| 12b370ddc1 | |||
| 50f86dc14f | |||
| 9078ddaf5a | |||
| 8028033513 | |||
| 6b9202dfbf | |||
| 04c928fb9e | |||
| 354d00963c | |||
| 9e5e49a65d | |||
| 8a849bd1bd | |||
| 1b3fb11a31 | |||
| b30ceab864 | |||
| 3e1791aa5c | |||
| 2cb5cc774d | |||
| 5f7843a13d | |||
| 1b770fc3b2 | |||
| 79d3c3be66 | |||
| 55d42492ac | |||
| 9737c2ad0b | |||
| b9a813a69d | |||
| e0ac454ed0 | |||
| 1db95aa09d | |||
| c0bbe1e23d | |||
| 9e35361eb8 | |||
| cce42f4a6b | |||
| bd19081543 | |||
| dd9b0ae4e5 | |||
| 3b5d28f0ee | |||
| 0ca39c70a5 | |||
| 270348b112 | |||
| e67473d89a | |||
| 086478e8f2 | |||
| 5a8da5dcdb | |||
| f6f4734fee | |||
| f903951016 | |||
| e19460cbd7 | |||
| 6de2b7700f | |||
| 70c1f9d0e1 | |||
| 761a079789 | |||
| 4116d66c59 | |||
| fc6edf65d7 | |||
| 9834ceed42 | |||
| 4266a7c166 | |||
| 639cc9faa8 | |||
| e2cecafa66 | |||
| 4bcb68a973 | |||
| 7131772754 | |||
| c2e5602ee5 | |||
| 8714fd77a0 | |||
| c20839c461 | |||
| 51229a29f8 | |||
| 59675949da | |||
| 6564ce0fb0 | |||
| c36ac4bdfd | |||
| 764ce2a4b0 | |||
| d400a5a108 | |||
| 744eb7c6d8 | |||
| 1b79e2ca5f | |||
| 4cb0edc90b | |||
| 6201280468 | |||
| 9e36e28217 | |||
| 5edb2c5688 | |||
| ce5e7998ba | |||
| 4a4aca6829 | |||
| 1f969fdc75 | |||
| e206d6ba35 | |||
| ef5eb4b612 | |||
| 864b29f7f1 | |||
| 4d498b668a | |||
| 62d0b0ae72 | |||
| 2c9ef2e1bc | |||
| 9b68671082 | |||
| 5c533e477d | |||
| 03ab6add5c | |||
| 052633b73c | |||
| bf9a8032a1 | |||
| eb261f5b28 | |||
| f5febb633c | |||
| d2ac3c2228 | |||
| 51caa930ca | |||
| b7af4e7f6b | |||
| 82cd30a145 | |||
| 8caae16113 | |||
| dc789c43b6 | |||
| 2e73fb25af | |||
| 1577d60d02 | |||
| 3bd1918c5e | |||
| 263b3141b5 | |||
| 82263a8b38 | |||
| 61ad2a1345 | |||
| d589914956 | |||
| f54a026acc | |||
| fc06d7011d | |||
| ed7c9ec619 | |||
| 1d9f6346d4 | |||
| a3a3156ddd | |||
| 70bd4a5ab6 | |||
| 21247721b4 | |||
| 4436d24440 | |||
| 7a16618ec6 | |||
| 2b2abc6b9f | |||
| 034aead930 | |||
| c8a5bafc6b | |||
| 0a7b9338f6 | |||
| bc0fa1240b | |||
| 292398dbe2 | |||
| 49da19e013 | |||
| 056840975f | |||
| 160b23f991 | |||
| bbd4c1054e | |||
| 152ac61faf | |||
| 4d65b1ab9c | |||
| 8b2f62000a | |||
| 166803a2a5 | |||
| 11a2b2a942 | |||
| 0a492acaa1 | |||
| e86d7f1fb0 | |||
| 962d599996 | |||
| ba536d67b4 | |||
| a573d076e4 | |||
| 625cb03284 | |||
| 2f8d60ec47 | |||
| 37e33af342 | |||
| f7e0516254 | |||
| 8e4bdcfb98 | |||
| f3f0ab6e2c | |||
| eafe57e923 | |||
| c76ab138eb | |||
| 5a771732bd | |||
| 9b6647a019 | |||
| 7e40a5a711 | |||
| 27cbd0d931 | |||
| 16c176dc89 | |||
| 12c316cd6b | |||
| b06583133a | |||
| a2e6fc5909 | |||
| 058065ce75 | |||
| 75a2015260 | |||
| 18776aa6b9 | |||
| 4cf48daa75 | |||
| 361aeac0cc | |||
| 2e66d621b5 | |||
| 566a11a585 | |||
| abb9fb3345 | |||
| 05a9652f76 | |||
| ba5df8edca | |||
| 9afee7e8d2 | |||
| c458186f68 | |||
| f9da0a59e4 | |||
| c19af95db0 | |||
| 840459bdb0 | |||
| 798660c007 | |||
| c039977048 | |||
| 7a9737b3d4 | |||
| 0f5d562625 | |||
| 21f9e7f5e5 | |||
| 6ee7b05b27 | |||
| e4c7e9903e | |||
| a96100d875 | |||
| 10c67051f2 | |||
| a3fbd09ef9 | |||
| 51248270e1 | |||
| 8fe431e53e | |||
| 61a7d88490 | |||
| 496765c043 | |||
| a62039882e | |||
| a2a05e40e6 | |||
| 45d08ea992 | |||
| c9c7aa2e90 | |||
| d0037fcf6b | |||
| b25fba6175 | |||
| afcdbf1ba6 | |||
| 8eff75a484 | |||
| e232cabfab | |||
| e5ed388191 | |||
| c0ac3de272 | |||
| abde9a99c3 | |||
| bdc74a03c0 | |||
| 2783461e69 | |||
| 0f9c75dc08 | |||
| cf937c6341 | |||
| 77210ffa56 | |||
| fb5bb1cd83 | |||
| 23c4615f5e | |||
| fa2b68dac6 | |||
| bd86cb22e0 | |||
| ec2635131b | |||
| 6b3cfdfb2b | |||
| bce66e3b42 | |||
| cffa035c1b | |||
| 1097192554 | |||
| 0c10b951a9 | |||
| ab2907cd51 | |||
| ea8d3d4531 | |||
| 256e4a0081 | |||
| e7adfff9bf | |||
| 721c9e2c97 | |||
| 42c7e39c99 | |||
| 96778c69bc | |||
| 4adcc403c2 | |||
| 2cca005056 | |||
| d27109640e | |||
| 931e0d4687 | |||
| 2e3224a138 | |||
| cfa3765d50 | |||
| 1287e8c734 | |||
| 11e884aec5 | |||
| 55a1ba710b | |||
| 0a8b266c71 | |||
| 7a6ac3ea92 | |||
| 394c12f68d | |||
| 1a57ad233d | |||
| c268463413 | |||
| 81fe93127d | |||
| aa5716d3f9 | |||
| f9c6f6856b | |||
| b9cc2606f2 | |||
| 5023313c03 | |||
| 98f9f7d42e | |||
| 3e0fd63682 | |||
| 1f643b5816 | |||
| 14adcb9db8 | |||
| 41a22bd83d | |||
| 648b83d6ea | |||
| 4e97b83312 | |||
| 07cd6cd670 | |||
| 3fae38a2f8 | |||
| 23054138c2 | |||
| 63f755554b | |||
| 2ac463f003 | |||
| 77227c2ff5 | |||
| 2afccd7fbd | |||
| 991181104b | |||
| 70aff9fbb2 | |||
| 2370884722 | |||
| c529b1b73a | |||
| acc29fbceb | |||
| 7cc5177078 | |||
| fc93ea7aa3 | |||
| 4c22982732 | |||
| fb935541c9 | |||
| 47023b2e6c | |||
| f4a390201c | |||
| d358ebd7e6 | |||
| 9711dd1381 | |||
| 4c328d83ba | |||
| 9911b132d2 | |||
| 534e5978d8 | |||
| c08bf1204f | |||
| 94d68c1f22 | |||
| 0ca379ed03 | |||
| 0ed2d8b127 | |||
| 3bee571e1f | |||
| 0b78544796 | |||
| 361f71deed | |||
| 61f39ae0a0 | |||
| 082324d7b9 | |||
| 5e99289d7a | |||
| e14a4e79ae | |||
| 39c85cafa2 | |||
| fa6be4ec58 | |||
| 25b8461bfb | |||
| ac43dd0777 | |||
| 963559676e | |||
| 20ce8c4c51 | |||
| 098c09835b | |||
| 4aa9d34b3d | |||
| 38d2a0ddb9 | |||
| 735bb147e2 | |||
| 7a511308ef | |||
| bc401fa392 | |||
| 96fbafe359 | |||
| e82b0ea4cd | |||
| 2160484b62 | |||
| f0ab58dfbb | |||
| c23b5825bb | |||
| f1872f495a | |||
| 9ed36445b9 | |||
| 5043c10d70 | |||
| e748d2f2af | |||
| ecde06e3a3 | |||
| 3505c1d790 | |||
| 150a72f75e | |||
| f96579824b | |||
| 2aa3cabd85 | |||
| 06d26df046 | |||
| 6e49b1cad7 | |||
| d928f425ec | |||
| ed3a9aed12 | |||
| aaccaa19bf | |||
| 35857d3103 | |||
| d47b0eeee7 | |||
| 287beaff35 | |||
| 8e9d1c7ebf | |||
| 53380632a1 | |||
| 984a95b8c7 | |||
| 72118fcc6a | |||
| 1b06f809de | |||
| 19fe508fb2 | |||
| aaaff9b66c | |||
| c660b43105 | |||
| 92b24fd02d | |||
| 886d0de040 | |||
| 16d797cb01 | |||
| bbf9678756 | |||
| d60c619c44 | |||
| e7abc05931 | |||
| 12dd912ce9 | |||
| 64a63b3879 | |||
| 93caf5b311 | |||
| aab2fa1af9 | |||
| 4cf176de0b | |||
| 735cfcd290 | |||
| 4aa4317c28 | |||
| d0ef6d2a9b | |||
| 434c84043d | |||
| 747116aeb0 | |||
| a182dc78f4 | |||
| 1a316c8a18 | |||
| 46e7fa52b3 | |||
| 52ea3748b4 | |||
| 0a2678973b | |||
| 04129c5bd5 | |||
| 6f363dcae3 | |||
| 8c4bd76280 | |||
| 92f385e7b5 | |||
| ac4e259e29 | |||
| 076b20a9a5 | |||
| 0b0230adce | |||
| e51915a529 | |||
| 187a475b84 | |||
| 39c0a619eb | |||
| 29f7eaad78 | |||
| 8f086a6957 | |||
| 8f512001b6 | |||
| 1d25522a3b | |||
| fdb538538a | |||
| 2feb1bf847 | |||
| 74bbb1167f | |||
| 515163864f | |||
| 1cdb975c91 | |||
| cd42d26eb3 | |||
| 8bc96652cd | |||
| 1631a2bac1 | |||
| 501635ca26 | |||
| edcd335b90 | |||
| 0cb9908f27 | |||
| 61858f5899 | |||
| c5911679d1 | |||
| 99d6a077fe | |||
| 8b680254ee | |||
| b873651da7 | |||
| b185d9e701 | |||
| b635622cac | |||
| b31d8b1ad0 | |||
| 2153cb7e0a | |||
| 15033eab28 | |||
| 8b4c530062 | |||
| 9ff9587b7b | |||
| d8acbda548 | |||
| 7e4a65114a | |||
| d9a2d29d00 | |||
| 27931249ce | |||
| 52318d0e0e | |||
| 8d673789be | |||
| 646c4c7458 | |||
| 2cc22d118d | |||
| 1182f41f99 | |||
| 098d1d2b5e | |||
| 31c85f0ec5 | |||
| 091d1f8c75 | |||
| 6c50e6ef34 | |||
| 67f48aca96 | |||
| fc64e787a3 | |||
| d13bed9a0a | |||
| 904c48b11a | |||
| 2ab5eb7213 | |||
| 5ce541e9ef | |||
| 0cf9c22033 | |||
| 38e06f13d6 | |||
| ccc94f6832 | |||
| 589820639c | |||
| 68b9260c9b | |||
| 49b2447113 | |||
| 89c50bbd82 | |||
| 2b3f3e11d3 | |||
| 4100cfec86 | |||
| cad3a50e4e | |||
| 4d9ee55468 | |||
| b72f009d87 | |||
| 2181e0fc27 | |||
| cd74cdfdaf | |||
| 49ab935ae9 | |||
| 6879c9d8df | |||
| 939bf4bb5d | |||
| 7861dfd667 | |||
| c5fc28de7d | |||
| 535d290293 | |||
| a0dd975686 | |||
| f48531efaf | |||
| c6a4116082 | |||
| aecd6b85e6 | |||
| 55439ef293 | |||
| d4cf103676 | |||
| 489fb087a4 | |||
| ff904ae174 | |||
| d8db5ec7b6 | |||
| 5d8b78cb88 | |||
| 9736402dfd | |||
| 0600054ad4 | |||
| b782fca75b | |||
| 0230b88078 | |||
| 55c9fb7c5c | |||
| 8201a9ce6e | |||
| 561a94cc50 | |||
| 0636887931 | |||
| 0c1b39d881 | |||
| 67ffae7e32 | |||
| 488a38a96d | |||
| 77e5854a16 | |||
| 2a42dab108 | |||
| 092d103d24 | |||
| 12b7df550f | |||
| 006bd2fe17 | |||
| d252768ac5 | |||
| dd7c2c0574 | |||
| c91898a888 | |||
| afa8eb2d6f | |||
| 1481015dc4 | |||
| 8cdedd4cd2 | |||
| 985e4eed60 | |||
| 9d0583e0d2 | |||
| 9aed26a234 | |||
| 3323d5c76c | |||
| 4b9afd787c | |||
| cedf01d094 | |||
| 4a71603a77 | |||
| aadc8477b9 | |||
| 9bf111bd3d | |||
| 8060da2132 | |||
| b495a302b0 | |||
| 9453b2387b | |||
| a4de59c8ee | |||
| fab40080e4 | |||
| fb30bda7d7 | |||
| 65206fe33e | |||
| 2f094134a3 | |||
| 69e1f42aed | |||
| c35c58b023 | |||
| 4b57aec1c6 | |||
| 2038bd0c15 | |||
| 19b24fcce2 | |||
| ed3354b433 | |||
| 963eeee361 | |||
| c3a316664a | |||
| 3d16880d95 | |||
| be6f355665 | |||
| 5dba08fb3b | |||
| f17077c05c | |||
| 8aa36072fc | |||
| 44ea82f845 | |||
| 0de7df9eab | |||
| 60e509b1e0 | |||
| 551c379f1b | |||
| c39a360372 | |||
| 683ee75703 | |||
| f6d1724835 | |||
| a99da47b0d | |||
| 0f217c715e | |||
| c4033c215e | |||
| e914d551e7 | |||
| c6e4b8ed5c | |||
| ab398f3704 | |||
| 699aec331d | |||
| baea6a1da8 | |||
| d2375a79f2 | |||
| ba48093666 | |||
| d4b87f1672 | |||
| e4006eb583 | |||
| b934e4b564 | |||
| 28c97a9467 | |||
| 28fca190ee | |||
| 78116e0ea2 | |||
| 5a50afa1fd | |||
| cf77a0e2b4 | |||
| e2593a6883 | |||
| 00a44d1ddb | |||
| d8445fd9df | |||
| 304db907f5 | |||
| b09cdc0f25 | |||
| bd81c6f5b4 | |||
| 4051dd9522 | |||
| 360cb9eb9a | |||
| 241a939c29 | |||
| 2f9c5d2d0b | |||
| 99c812b02d | |||
| d82c2ce50f | |||
| 6c12156b1a | |||
| eec3b3009f | |||
| 5ac7fe453f | |||
| 4654b41c3e | |||
| b09ea17f0e | |||
| 99ebfc337e | |||
| e5f9458905 | |||
| f9c083073e | |||
| ec0a9a5f8a | |||
| 47b924990f | |||
| 215bebb01a | |||
| 9fffa19c51 | |||
| b54f3d4ee9 | |||
| bcdcad5847 | |||
| 737b8e42e4 | |||
| c61e7c05da | |||
| a919828003 | |||
| 0bd33882b6 | |||
| e0e55a649c | |||
| f32d71eca0 | |||
| 74338733ba | |||
| 5fb98609cd | |||
| 19633ece80 | |||
| fb04103352 | |||
| 9abf43b0d2 | |||
| 7f97274ecc | |||
| b2edab193f | |||
| 184563bbe1 | |||
| 73f25ed182 | |||
| 533f6a552c | |||
| 32ac319525 | |||
| 569397bd7e | |||
| 3535d16c3a | |||
| 7f4efa90c8 | |||
| bab3cd988e | |||
| feda213c0c | |||
| c6593e8cde | |||
| 4d8d3919c0 | |||
| 20dc8b222d | |||
| 55733171c1 | |||
| 988926b59d | |||
| d72f8da6d7 | |||
| 0b697b24bd | |||
| b2c75dc3a2 | |||
| b5b3f1fb42 | |||
| bd73834e19 | |||
| 7f43c24297 | |||
| 1b3657122c | |||
| 0f28857c59 | |||
| 88485d5467 | |||
| 921530dd01 | |||
| dcf3023d93 | |||
| 6ac2c5c6dc | |||
| 45b3ae31af | |||
| b12c46b28a | |||
| 66a20264ab | |||
| d2d243cca8 | |||
| d4194962b0 | |||
| 635d671ee7 | |||
| ee8372145d | |||
| ccb736411b | |||
| e2e5641a45 | |||
| 7ca0b256eb | |||
| ca442defbb | |||
| b17ebeb6f6 | |||
| a8afcf1ca9 | |||
| 6545cc2d48 | |||
| 2a10c8fe5c | |||
| 7cd2d14b64 | |||
| fc5abfd68b | |||
| cb5c821989 | |||
| ab7652010b | |||
| 7990566f6b | |||
| b6baee5f77 | |||
| 24c3ec235a | |||
| 204c0fa4d8 | |||
| 3a0b66d5df | |||
| 07d3122c14 | |||
| c6957e4e31 | |||
| 8068a3899d | |||
| 4c0e9f1f89 | |||
| 3cce972125 | |||
| 52700d6a84 | |||
| 0c80a4b836 | |||
| 46f408cc9f | |||
| 5c068a9062 | |||
| e1fae5b902 | |||
| 20e5e95ff8 | |||
| a238f78855 | |||
| 5b96712ed0 | |||
| f141078073 | |||
| d47fed16a9 | |||
| bc43a8d38d | |||
| ccd5685cee | |||
| f0f8177a19 | |||
| 363b701925 | |||
| 0a897e2fae | |||
| 5f53d815d1 | |||
| 7b89f25818 | |||
| 8ebb84ad1e | |||
| f0e77a309d | |||
| 7ab531bd21 | |||
| d7af6de9b9 | |||
| 3072479c3c | |||
| 62031c24a2 | |||
| aa38889704 | |||
| 17562e476f | |||
| 6495f2cf98 | |||
| ea20b644cc | |||
| bf848637aa | |||
| 759f846b2b | |||
| 3758be55f5 | |||
| 8f4c59b080 | |||
| 1ff6212ffa | |||
| b60d29ae9a | |||
| 38d71e668d | |||
| 7cdf37eaf6 | |||
| 8d9adfd548 | |||
| a3e2d90f4c | |||
| fc81008ab5 | |||
| a1eae6304f | |||
| 49058620f0 | |||
| f68a3639b4 | |||
| f4e87c9720 | |||
| 23bf7973fa | |||
| 67e0751124 | |||
| f76559daf6 | |||
| 5e99ff6769 | |||
| 1ecb4aa9aa | |||
| a2b3c72647 | |||
| 0180a4fcd4 | |||
| abca3ceac8 | |||
| 866a9fdf19 | |||
| 20e954a864 | |||
| 03e40b333a | |||
| ebed66d4ce | |||
| 9e9f3c485b | |||
| d50a844720 | |||
| 89e559296e | |||
| d352e2fa31 | |||
| 71bc452764 | |||
| f048ad13b5 | |||
| d03d5d8f03 | |||
| 6ff0ce15e7 | |||
| 330b393e16 | |||
| a820246f64 | |||
| 1bf4c8c9ba | |||
| ca1d437435 | |||
| 8b8310711e | |||
| cdcb64b0d0 | |||
| 3c0f1caa41 | |||
| 8182ba4ee0 | |||
| 3d9328fd79 | |||
| 6c6f9f7d25 | |||
| c8f475174e | |||
| 3dec55f009 | |||
| 00d60e28c2 | |||
| ea00619c3b | |||
| bbe50bdaf1 | |||
| 6b59aee336 | |||
| 26a5614572 | |||
| 19ea090633 | |||
| 9841b11a54 | |||
| 5a6d5374d7 | |||
| 9099bc0b6e | |||
| e3b43b6e1c | |||
| b0d801f629 | |||
| c48057081e | |||
| ea76e09ea7 | |||
| c9fb078c0f | |||
| 1800030356 | |||
| 43ba2c6226 | |||
| 735181dc0e | |||
| 8a890fd3d3 | |||
| 15e31e47fa | |||
| 9b54b99bf6 | |||
| 67ca9166d3 | |||
| b2ced834ba | |||
| 18746c1444 | |||
| 09f366bec7 | |||
| 3998d0c81e | |||
| 2a002c3882 | |||
| fb756e3463 | |||
| 3c5661b51b | |||
| 26e06ba6a6 | |||
| 7c57dde255 | |||
| 9ec927b9e9 | |||
| 15a0d9f900 | |||
| f26e3c6509 | |||
| 6568625dea | |||
| 427f212170 | |||
| c1fb8eaf1a | |||
| 37469dc9c2 | |||
| dce57627c9 | |||
| 2992ca5df1 | |||
| a5ed5883c7 | |||
| 0036509f74 | |||
| 003c470a4d | |||
| d6540d9077 | |||
| 091c515fea | |||
| 4f2b9835f5 | |||
| 242d3b3c4d | |||
| c66ac9725e | |||
| feacc5cd11 | |||
| 3a761395be | |||
| a78d6fe0b3 | |||
| 08e466938f | |||
| e036155bdb | |||
| 2149afabe1 | |||
| ec32967daa | |||
| fc4a5e61c2 | |||
| e9608c9d05 | |||
| 581eebb197 | |||
| 10fa67fdaa | |||
| 10f2136675 | |||
| d97dd99d91 | |||
| 296674e18b | |||
| 52a926dd90 | |||
| d38ea63c78 | |||
| 2022a7615a | |||
| dca0fae781 | |||
| e16c6c1b6b | |||
| ede9881458 | |||
| a7f8c78358 | |||
| 3a90b40425 | |||
| 454709559b | |||
| c3933cead4 | |||
| 420f93ce78 | |||
| 2a212a7556 | |||
| 145a7a24e8 | |||
| 6c040497ef | |||
| 9ee4b76cd9 | |||
| 3f6775e29b | |||
| 4c17e2e97e | |||
| eac53fed59 | |||
| fed0c2ea26 | |||
| 21c1618d94 | |||
| d37699f51a | |||
| d82bfa98a7 | |||
| 9b15bda055 | |||
| 635842b322 | |||
| 3b8515beb0 | |||
| 7b62b81ebd | |||
| dcf4e51787 | |||
| 7dc09ed450 | |||
| 349641e95f | |||
| 9941ec85d8 | |||
| ef944b903b | |||
| 0c477f2c6b | |||
| 151396507e | |||
| 8441c0c51e | |||
| ae7bf468d1 | |||
| 907ef82d4b | |||
| 7a1ab62987 | |||
| 295cfc905c | |||
| 204924927a | |||
| f622a8393c | |||
| d75df7fd8a | |||
| 2bc5e0ebd7 | |||
| ca6cef9a7d | |||
| 1c2a30d7e9 | |||
| 4a75a1e839 | |||
| 6a2ff3a371 | |||
| 7ce1386d1a | |||
| d6f45e4d76 | |||
| 356f66784f | |||
| 166ab7b600 | |||
| 1cdb0abf80 | |||
| 0defd1d141 | |||
| 24ed07b6d5 | |||
| ecad730945 | |||
| efb7fd919b | |||
| 5d6b923244 | |||
| d8752da7d5 | |||
| 6952124988 | |||
| a6c93e2c41 | |||
| 788f3c22bf | |||
| c194dfbdf7 | |||
| 5e996a1c02 | |||
| b52bf11ea5 | |||
| 7915dde43c | |||
| 7675b9c28f | |||
| ebe5636307 | |||
| 6fe2df1d7d | |||
| 5376d32772 | |||
| 2924e478ee | |||
| 297700ad11 | |||
| 9d29914304 | |||
| b223bc0302 | |||
| 3562a38f8c | |||
| 201544ef8b | |||
| 837ba6c33b | |||
| 3ab01dbc00 | |||
| c241edaa30 | |||
| e0530df98a | |||
| 6cbce9fdff | |||
| c1eb536726 | |||
| b848ae7abb | |||
| f07453d0ae | |||
| 052051244f | |||
| 97490c6445 | |||
| 1247d36a12 | |||
| f3a463000d | |||
| c38842ecb2 | |||
| 8b825b23b1 | |||
| d2f62730bc | |||
| d167d18bb3 | |||
| 508d7c3336 | |||
| 2b31d85cd4 | |||
| e350c37e6f | |||
| 319a465429 | |||
| 9371325246 | |||
| 2fda3cf988 | |||
| 03b7194c97 | |||
| 39bff40a75 | |||
| 3dc6edfd2d | |||
| 762747273e | |||
| 0f392a95ae | |||
| 29786b0024 | |||
| 32ca50a097 | |||
| 8012e6fa43 | |||
| 54b7cefb09 | |||
| 3a61350f4b | |||
| bdbbaf6c88 | |||
| 24a1a8a626 | |||
| 38b64dc5df | |||
| e3360a0e5d | |||
| 4181444734 | |||
| 7958708641 | |||
| 40a8ed535a | |||
| c7d571f0b5 | |||
| 5d54b710e7 | |||
| 248f14a1ef | |||
| b76fc58543 | |||
| 9fc9981a9e | |||
| 8f563df7c5 | |||
| 730192adc4 | |||
| 8bf32ac697 | |||
| 540f724b1f | |||
| d5a8f2298e | |||
| 18c5a53685 | |||
| a1172d31f4 | |||
| 396debb9cb | |||
| c4cb2f2378 | |||
| 74ce99e0d7 | |||
| 89a233ccd2 | |||
| 2df6cabee0 | |||
| 82023cd629 | |||
| 1e17f44991 | |||
| 600c97cc0f | |||
| 7298054974 | |||
| 4d5a442d1f | |||
| 249f42f054 | |||
| 87788142bf | |||
| f0b08a6c67 | |||
| a144a49a9a | |||
| 2167f1b567 | |||
| c5c723b80c | |||
| 66461c9dbc | |||
| d77103e53e | |||
| 963908e508 | |||
| 9e5677ab02 | |||
| 46bb9bc5c7 | |||
| 118ab60588 | |||
| 223ae61c89 | |||
| 1f4baba06e | |||
| fa1ce7d5d1 | |||
| 775a488a36 | |||
| 018904f0ec | |||
| b358641e7d | |||
| ff745e0ad8 | |||
| 4201834b18 | |||
| 2631e07bea | |||
| 76a1851cb8 | |||
| 87a1792677 | |||
| 413077a5d9 | |||
| d56fdd2937 | |||
| 6639b7d017 | |||
| 7702a488e5 | |||
| 3108752a0c | |||
| 56c0d32ea0 | |||
| c0e84b0592 | |||
| f2e590be7a | |||
| 60ec3594ab | |||
| 49d1f6aca0 | |||
| 49cd9648b0 | |||
| 1692dcf8d5 | |||
| 5ec4719124 | |||
| 911c98e235 | |||
| 535c64c318 | |||
| 171f38b9b5 | |||
| b2645b3201 | |||
| a9936d1570 | |||
| 3032a4274d | |||
| 31c21a054b | |||
| def4fdc3f3 | |||
| 3fed1af7df | |||
| adb4692ce8 | |||
| bb4ff84a4a | |||
| 5d2c1b175e | |||
| 2ab6de8ee4 | |||
| 1896ae5d15 | |||
| 6e4fab19a2 | |||
| 103dcfe897 | |||
| 8caadbacf7 | |||
| 870d776875 | |||
| 59e66ffe49 | |||
| 418a0132d0 | |||
| a381846034 | |||
| 1c5ce75d9f | |||
| 8693a045bb | |||
| b567679eb6 | |||
| e6c8d3d1db | |||
| 12c4afd824 | |||
| 968a07ed7a | |||
| f9c600a760 | |||
| 82561cfbac | |||
| 277ae4e2b0 | |||
| 0f9e747583 | |||
| 4e146a75b6 | |||
| 33d0e2037b | |||
| 7a04b7262e | |||
| f2d5e4b995 | |||
| ada42aa184 | |||
| ed580b3060 | |||
| 29e4762011 | |||
| eff4833840 | |||
| 9867037aa2 | |||
| 57c14f6a9b | |||
| 1ed105205c | |||
| 8233f49beb | |||
| 2c01a4613c | |||
| b0eda47b26 | |||
| 291111e626 | |||
| 47693da4aa | |||
| 9f39209712 | |||
| c47dcbbe2f | |||
| f313538ea5 | |||
| 956ffdf654 | |||
| ef4a527c36 | |||
| 3fe0680ad5 | |||
| 182b269e46 | |||
| 05856ac93e | |||
| 60c29e195a | |||
| 6b23662ce6 | |||
| 77d6364405 | |||
| 077a611a5e | |||
| e82146bf17 | |||
| 0c3522133d | |||
| 1223e8cf7f | |||
| bcb01bdc52 | |||
| dfb5f8ea2c | |||
| 02eab95dd1 | |||
| 67a1e6e46a | |||
| fda1e4409c | |||
| 703c1b0fcf | |||
| e1654e9dd3 | |||
| f8bdd42027 | |||
| f5dcbf517b | |||
| 075193af1d | |||
| 808e7ed4ae | |||
| f0ba5d3821 | |||
| 88f6b5f16b | |||
| 68e6e1b779 | |||
| 9528325777 | |||
| b3aa6afba9 | |||
| 716fe2f427 | |||
| 7df1cc075c | |||
| b0f0a02d3c | |||
| 7cda64e52d | |||
| d6d34bd62f | |||
| 68dde07d5d | |||
| fad4ae8eb2 | |||
| acd8a4bc95 | |||
| 6714e05183 | |||
| f9b5f2b7b1 | |||
| 67fa5df89c | |||
| 023cc9ca54 | |||
| b7924de5c6 | |||
| 4b4481ea27 | |||
| 47be46ae60 | |||
| e84802468b | |||
| 623d789529 | |||
| 827f36e2c0 | |||
| 1a5ed4eb7f | |||
| 5151403aaa | |||
| d5772c939a | |||
| 19097bc5bc | |||
| dbebe9e92c | |||
| be0a543077 | |||
| 67b6a8ee89 | |||
| 780375d865 | |||
| cbcf94669e | |||
| 46da53ba15 | |||
| 06e8d03fba | |||
| 65bf7f6653 | |||
| a6b9341593 | |||
| 47610725ea | |||
| 341ba34773 | |||
| 3b2864d8a6 | |||
| c7d4af5c79 | |||
| f2ec438166 | |||
| a95b064d6d | |||
| c503a75873 | |||
| 9a982cc5b5 | |||
| 685f7d0fea | |||
| f5d9ca64f9 | |||
| cde442fa2c | |||
| 84f966cb8f | |||
| b2b88f1d99 | |||
| 9d23a392a6 | |||
| 57214c63cb | |||
| 6726df4d58 | |||
| 02a58c1247 | |||
| 72a7b35513 | |||
| 2d699fd13b | |||
| 13c321b8fb | |||
| fa42a788c8 | |||
| 843eaf8893 | |||
| 30fa8f8ac2 | |||
| 0ec4e8d5d4 | |||
| af63eff8d7 | |||
| b5d2dd617d | |||
| 8d951ab7f1 | |||
| e24315eed8 | |||
| dc55e88588 | |||
| 7abaf77292 | |||
| e79883e4fd | |||
| 5da76ae34b | |||
| a6d5f9877f | |||
| 994825671d | |||
| b7b5043aea | |||
| 1bf4a6f711 | |||
| 073f51e284 | |||
| b5784bc2ef | |||
| b42bb5be26 | |||
| b6f356c211 | |||
| b052da1065 | |||
| 586e85281e | |||
| ec3ea3752f | |||
| 8294480cb4 | |||
| 6fe8692b98 | |||
| d8e0a86600 | |||
| 8b29b07f5a | |||
| 1d6936fafc | |||
| b22d71a74e | |||
| 7fc2081543 | |||
| b8c2b0105b | |||
| d72db2698b | |||
| e0d9092df8 | |||
| f863264af6 | |||
| 14736c2a8b | |||
| 0af1b75a02 | |||
| 7a8aa03e54 | |||
| 846c0f7cfc | |||
| 1886193c6c | |||
| 100e907890 | |||
| 383c222553 | |||
| ae6e76bbb3 | |||
| ed7284add2 | |||
| 9ecbd70daa | |||
| b8989d9bf9 | |||
| 0f1c5b3891 | |||
| 41ff7a6010 | |||
| 0234f50da1 | |||
| d7cc166eab | |||
| eef44425c3 | |||
| 167b320cdd | |||
| dcf53236ff | |||
| 5b1a531755 | |||
| 97b2d1fe5c | |||
| c5af69ffa6 | |||
| 12d56103d9 | |||
| 8ff713f3bb | |||
| 03972d565e | |||
| 4dcf253330 | |||
| 012f386057 | |||
| 3fa684d6ba | |||
| 8c327567c0 | |||
| 31bc982a53 | |||
| cbd2d89637 | |||
| 67151d39e1 | |||
| d715158fe3 | |||
| 75c0eef6ac | |||
| 4030c5a689 | |||
| 119cafd963 | |||
| 5fc54ec7e5 | |||
| fb0b9de7a9 | |||
| 2c9156e2c1 | |||
| 236347b5bc | |||
| c5d2b01923 | |||
| bf75fd9d34 | |||
| 9a8c69d1c0 | |||
| 6c943722f3 | |||
| 219343f3c0 | |||
| 36b2f13ee0 | |||
| 70ce878dfb | |||
| 9c1612f122 | |||
| 6cba4d3483 | |||
| 738cf837de | |||
| 2550918f27 | |||
| aa5a222c6d | |||
| 2795f09fa8 | |||
| adcaace03c | |||
| f205df1996 | |||
| c59ad24856 | |||
| 2b9b0ac62e | |||
| 08bc6a1698 | |||
| 67e6f57192 | |||
| 24ddb8506f | |||
| 6ff0cc0b40 | |||
| 7620fe1ac6 | |||
| 22e0f5ecd0 | |||
| fce2042375 | |||
| 57594153a1 | |||
| ff93ea5bf1 | |||
| 4a54676f31 | |||
| 0d900521bc | |||
| bd7ffcc048 | |||
| 2f771bee7b | |||
| ae5214c1f2 | |||
| 24493e89ad | |||
| 84d8798ad3 | |||
| 0570c84a83 | |||
| a3860e23c6 | |||
| ab7e1e01de | |||
| bbafc3fbd6 | |||
| 194fa7cd98 | |||
| 4c12addcaf | |||
| 0bd27381c3 | |||
| 6dce07790a | |||
| 203ae32b79 | |||
| 3c493194c9 | |||
| 692764aad3 | |||
| 937e5de1d8 | |||
| 7de67f8c1b | |||
| f5d66bcb6f | |||
| bf82c40964 | |||
| aa6299f114 | |||
| 7ffca8ed58 | |||
| 030405dbb6 | |||
| 8862f9118b | |||
| e2e98672bd | |||
| 51f295cacc | |||
| 0c50ac3396 | |||
| 2da81a4a26 | |||
| b6d4853a33 | |||
| 020b147222 | |||
| 34b037f19b | |||
| 88ee5d1a6d | |||
| 0892d84c17 | |||
| 2501d50f9c | |||
| 1e4a4181e2 | |||
| 3e1daa002c | |||
| 4c13dee18f | |||
| 95497626e3 | |||
| 9ada48054f | |||
| 99d6c58971 | |||
| b974b3ccfd | |||
| 75cf45f0be | |||
| d337a11e83 | |||
| a86386d882 | |||
| bbf40bf318 | |||
| b054585066 | |||
| 90c44c34a9 | |||
| e449cc9e2d | |||
| 909ed93cd3 | |||
| 9c97b11ab9 | |||
| 5ae44b25da | |||
| b2ecb37b35 | |||
| 144d034475 | |||
| 50d8dc91cf | |||
| e58915e12f | |||
| 7f8c2a44a4 | |||
| d986eee36b | |||
| b3e712e0b8 | |||
| 05434daa69 | |||
| 2c4a478987 | |||
| a80ca23937 | |||
| ba02ef8f25 | |||
| ef3d8bdc42 | |||
| 951511704d | |||
| 23aae6ab0f | |||
| 3748e117a9 | |||
| 33798b8b80 | |||
| 2e85083d0a | |||
| 23b8a9033a | |||
| 313b6874b1 | |||
| 6004412365 | |||
| adac039a2b | |||
| adcc865c70 | |||
| fe533fb809 | |||
| fa62963da7 | |||
| 1f5bb99548 | |||
| f1cd56c28a | |||
| 852c8b533c | |||
| 582a72574e | |||
| b249ddde48 | |||
| b020ba2b5f | |||
| 03c6862d51 | |||
| b7f953b2ee | |||
| 0b064765c9 | |||
| eb3ddce706 | |||
| 5fdc9fa3b6 | |||
| bfb231fb8a | |||
| 74fb74d9cb | |||
| 97d7e295dd | |||
| 0727e91aeb | |||
| 8dc70f797c | |||
| 2cf8a9da6f | |||
| c1c7128634 | |||
| 0e9ef50e63 | |||
| e05944601a | |||
| 49cf0125a9 | |||
| 0602a16ad6 | |||
| 09a0dad115 | |||
| 243a3f5006 | |||
| 33ca85bd4e | |||
| ca15eb26f0 | |||
| 28eebc14d0 | |||
| 4210aa9ab9 | |||
| 5bbdbadc25 | |||
| 00f24a3249 | |||
| d8a798372b | |||
| 8d5c865814 | |||
| 5134d6bc63 | |||
| ede57720fd | |||
| 830d2007a6 | |||
| 5f3b6c9722 | |||
| 93f7d3bfb9 | |||
| f0ef10aa57 | |||
| bf91fcc6f7 | |||
| 2d894a0164 | |||
| 731b9c902f | |||
| ac0f3c8433 | |||
| 56bfbbf501 | |||
| 63b5d472fa | |||
| 233e3c76fd | |||
| 2334dadb6a | |||
| 6f4f2754d6 | |||
| 30ced04137 | |||
| c39bd7e089 | |||
| 3470d986f0 | |||
| 7c0257fcda | |||
| 9af6d6c9c6 | |||
| 1ecab2fcbc | |||
| a262c0bbf3 | |||
| 7f3f164736 | |||
| 085db569f1 | |||
| 133af6f826 | |||
| 1c2301e2f1 | |||
| ef999f660b | |||
| fad330acd1 | |||
| 8f1af2630d | |||
| eea92a3371 | |||
| ff275df5ea | |||
| 6e56e5457d | |||
| afaa5f2deb | |||
| 0674b1b6ee | |||
| 1ef8602f19 | |||
| ee597fc9b8 | |||
| e254581a1b | |||
| 38ea140b3f | |||
| d939d6079a | |||
| 6e9475d61d | |||
| f6134422e6 | |||
| 5c05038af0 | |||
| 5da5ebff13 | |||
| 798932523e | |||
| 5267a864db | |||
| f02334237a | |||
| d5ea492ef5 | |||
| 96ac405952 | |||
| 38d58e818c | |||
| 2d71ab6f29 | |||
| 090723179b | |||
| 5b55fbff23 | |||
| 64f200dc74 | |||
| 99e2f0c91e | |||
| c02ff3af27 | |||
| 553f338f6f | |||
| bb72c804fb | |||
| 13c6352b8e | |||
| 707c2b3d7a | |||
| 14eed79a21 | |||
| 2ca30e3acd | |||
| caf9716bf1 | |||
| d569daae33 | |||
| 28f7f57247 | |||
| ffc592c7cf | |||
| 3567c006e6 | |||
| b9db450a7d | |||
| 0d65c6dcf7 | |||
| dfee7c103e | |||
| 025fc2685d | |||
| 5b5154eda0 | |||
| ecf65303cd | |||
| 8ea6972496 | |||
| 9afd9f9bea | |||
| c8d3a9121b | |||
| f0950e2286 | |||
| edd78ae129 | |||
| 8738695bd8 | |||
| 76cb3b7874 | |||
| 02a098eb48 | |||
| 1f17a391c6 | |||
| a8fb346fd7 | |||
| 96fb5eb0ba | |||
| 9c7656d59a | |||
| a53bff5645 | |||
| a9182cfd8c | |||
| de6c0f682f | |||
| 9cfcb43725 | |||
| d9b590c76e | |||
| 450c535e9a | |||
| 0dc166e594 | |||
| 8ba080a66d | |||
| 7801582819 | |||
| bc882e678d | |||
| 58e173f279 | |||
| b7d7b9d6b3 | |||
| cf091a48b4 | |||
| d9bfe9e5d4 | |||
| 245a6697ef | |||
| 6226c2978d | |||
| 3d325e52c6 | |||
| 6a6d7701f9 | |||
| 50c688f0f7 | |||
| ef99d03f21 | |||
| af265250c2 | |||
| c6f463b8c9 | |||
| b7d75e2f1d | |||
| 6aa54cbe9a | |||
| 090e30f07b | |||
| f5d507a9b9 | |||
| 8e5e43f335 | |||
| b9f7b2fdfa | |||
| 59a601f2cf | |||
| b6a5c5f5d2 | |||
| a2f02b8b32 | |||
| ee4ed126e1 | |||
| c36dc91849 | |||
| 91dccf8d62 | |||
| 1fc3a25f47 | |||
| 7322b63991 | |||
| f860b09065 | |||
| 45b742be23 | |||
| d325ee4b91 | |||
| 87d6910bb8 | |||
| 9c9300ed58 | |||
| e559cf32fe | |||
| f2202db517 | |||
| fb735883be | |||
| 6a2ef1f4f3 | |||
| 051c9cb564 | |||
| eb60ec3899 | |||
| 233f47cc99 | |||
| c386c72d10 | |||
| 20eacc4a84 | |||
| a28699b42d | |||
| 4d74d5bc99 | |||
| ed371f2b0d | |||
| 66f2881a78 | |||
| 7d4e9497eb | |||
| c08809e29d | |||
| 99460c9e32 | |||
| d86df8321c | |||
| 806f56ca38 | |||
| c40b6c7c2f | |||
| 896b7145b3 | |||
| 8a2a70a3c2 | |||
| 97352538ad | |||
| c6c4ad6188 | |||
| 210f47b8ab | |||
| 94c1331c07 | |||
| d6407e9636 | |||
| df58a00564 | |||
| d546677ae7 | |||
| 04b1023988 | |||
| 9a81071687 | |||
| 48685e8bf1 | |||
| 0f697a0f26 | |||
| 8ddb493b96 | |||
| 039d9938b9 | |||
| f50ea649f6 | |||
| 6e647a88eb | |||
| 986cba584e | |||
| b427a4c8c9 | |||
| 133ee70a5b | |||
| 494612827a | |||
| 1113f23475 | |||
| 8626f58773 | |||
| 7032867421 | |||
| e6239ca3c2 | |||
| 162628000f | |||
| 55b79c078c | |||
| 570b127869 | |||
| 6179d4feb1 | |||
| 2ff5d016d5 | |||
| 854a95327a | |||
| 8a16fd7699 | |||
| 7bbcf22deb | |||
| 0324281634 | |||
| de0a3e0ab9 | |||
| d26110da7f | |||
| 60e73d91f6 | |||
| 5eeb436626 | |||
| 802333e454 | |||
| eb457d688d | |||
| fcc920ed39 | |||
| 4e70256109 | |||
| 2e4d6d2577 | |||
| 51ae21a029 | |||
| f59846377d | |||
| 8e8eb9e5cd | |||
| 88b578ca11 | |||
| 4cb16db4e9 | |||
| 338d483682 | |||
| 0ce59a9e2b | |||
| 8d43cc840a | |||
| 9ae1bfb69d | |||
| 6ec7284467 | |||
| 0ccc570ef2 | |||
| a3bb7d3028 | |||
| c45ca1bfcc | |||
| 94edf89b20 | |||
| 8d6ce0b693 | |||
| ccf4b48865 | |||
| 96eae94103 | |||
| db8b2e69dd | |||
| 82821580c7 | |||
| d23d7cf0f2 | |||
| 34cb558279 | |||
| 450a602230 | |||
| 36764779cf | |||
| 97595c4b50 | |||
| ea9fe397e5 | |||
| c482432966 | |||
| 55176e52fc | |||
| 4eb08bb096 | |||
| 881ef69063 | |||
| 761a19689d | |||
| f438153b81 | |||
| 117c0cceb1 | |||
| c949e404c3 | |||
| 3d2a6c5895 | |||
| 8f4ffbe1da | |||
| 8f3b6738ff | |||
| d50c6d72db | |||
| 15c5e92d63 | |||
| 041c7c8284 | |||
| f040ef41cb | |||
| 91ab184175 | |||
| 48a64a2c88 | |||
| 7f3795a231 | |||
| eb1d00ced6 | |||
| f41c91d36b | |||
| 6909e0d774 | |||
| d52921edd4 | |||
| dcca40033e | |||
| fed65742df | |||
| b918acd871 | |||
| a046c41c7c | |||
| 2513403014 | |||
| 4a8564aff7 | |||
| edb23db2ae | |||
| 0b01cfd853 | |||
| 0d059aa797 | |||
| 65c0255e7e | |||
| b289a27c4e | |||
| d085283f20 | |||
| b6ca10cd5e | |||
| 7416f72565 | |||
| b51be71a6f | |||
| e488cf4601 | |||
| 5d397804f7 | |||
| a5a7226885 | |||
| 2dca39b557 | |||
| b55fa268bf | |||
| c819c350d6 | |||
| d55248ab0f | |||
| 68b2d4b9e2 | |||
| 54f02f59db | |||
| 64047cbf05 | |||
| b0619980b2 | |||
| 9aa9429135 | |||
| 518f30e523 | |||
| 868aa4c14a | |||
| 1ab90de493 | |||
| 1064bcd060 | |||
| 1e21125527 | |||
| 4a8c37dd52 | |||
| 3b22c6620c | |||
| 402a165b60 | |||
| 34f9170189 | |||
| 38136e15fc | |||
| e97bf2ef35 | |||
| d6c54148d9 | |||
| cbe3791b42 | |||
| b470ceb470 | |||
| c15db05199 | |||
| 9428f792ed | |||
| 520ff731de | |||
| e9cfe698ba | |||
| 5fa66ac6a8 | |||
| 320062157f | |||
| d7d6608142 | |||
| 7f2ef2ac67 | |||
| 7124d541a1 | |||
| 3c7e45a46f | |||
| 6ec014e980 | |||
| 9b47a5eddb | |||
| 3e8c63ad31 | |||
| 15469758de | |||
| 86511d44e4 | |||
| fd4633eb25 | |||
| b0756f9e29 | |||
| c3ff1e9591 | |||
| dd3fac7523 | |||
| 13029d06b2 | |||
| 68173f4bc7 | |||
| c979c2fafa | |||
| 658435f1b9 | |||
| 3935957979 | |||
| a36640bcfc | |||
| 171d5b4012 | |||
| 1cc893f21c | |||
| 6ff2db47b4 | |||
| a11b6a9e5f | |||
| 978568684c | |||
| e8e7d3ea31 | |||
| c03cc21908 | |||
| 8ef406324b | |||
| 23d0c52bf4 | |||
| 5eee8077dd | |||
| 029cb6581b | |||
| 025e87d974 | |||
| 213a0499a1 | |||
| 1517f1d779 | |||
| 50a2493fd3 | |||
| b455ccd261 | |||
| a58650728e | |||
| b22ddb1453 | |||
| cb7dd12222 | |||
| 0484bdbb7e | |||
| 8f39c45e9b | |||
| 944396128b | |||
| bbb2164e38 | |||
| be23d83fc8 | |||
| 291ea33939 | |||
| 9455918eec | |||
| 8a99b8af3e | |||
| 12e42d92d3 | |||
| faa735d0c7 | |||
| d4e18109da | |||
| d06a0e7093 | |||
| b3a55b8b6f | |||
| ec69101101 | |||
| 17fa8cb6ef | |||
| 855ebceadc | |||
| 2720e98127 | |||
| bb80c1b059 | |||
| 85e390deba | |||
| dc317c8cd8 | |||
| 774fea1e63 | |||
| 485c606672 | |||
| 3dee3205b2 | |||
| c7a704d345 | |||
| 0fb3032b73 | |||
| 69934c3b0b | |||
| 7380b7e61b | |||
| 747a11a954 | |||
| 252be0fb41 | |||
| 600f2b7284 | |||
| 670274ad8f | |||
| e10fe91eba | |||
| fd62ee14cd | |||
| 8ece92f1f6 | |||
| 69b075782b | |||
| 6bd3a9d422 | |||
| bc9ee8e1a4 | |||
| d36c3c2590 | |||
| 52b319dbfd | |||
| 318d92f9a8 | |||
| 7ffffeeccc | |||
| f16d8e77b3 | |||
| 5b335bb88c | |||
| df2767311f | |||
| 09c26e6be0 | |||
| d2ec2d1606 | |||
| 0d87b2e8db | |||
| 1568971732 | |||
| 0e040be941 | |||
| 9737b65d9c | |||
| ad52003077 | |||
| c386509112 | |||
| c293f5b7eb | |||
| fa562ec5d6 | |||
| 529383f5b1 | |||
| f01cff7ff0 | |||
| 015fe924b8 | |||
| a5ce8a8c0b | |||
| bfdcf900ef | |||
| 54f89dd84b | |||
| da479c7628 | |||
| 3c90a05957 | |||
| d16ddf7926 | |||
| 5c519f0e8d | |||
| 74e6d9144e | |||
| 20d451396d | |||
| 60d0390ef8 | |||
| 782f1b4718 | |||
| 85f0a1067c | |||
| c08ff891ad | |||
| 168cec1e9d | |||
| 28fb35f2f7 | |||
| c1384afe2f | |||
| 547c7bce1b | |||
| 0bb93d40d3 | |||
| 27ba1d596c | |||
| 98e5523f2f | |||
| 223b66f422 | |||
| 04a4dbcdaf | |||
| ef9e31cb31 | |||
| e019673a18 | |||
| 5f27f2dd7f | |||
| cfccf73cdd | |||
| 465d003b1e | |||
| 1d6f7680a1 | |||
| f36e19e86f | |||
| 86fada718e | |||
| 2a94b66f4d | |||
| 4ee413aa32 | |||
| 5d0f9c428a | |||
| d904ae5191 | |||
| 8a822bdd9a | |||
| d1a3842e39 | |||
| 2d824e4809 | |||
| 00823ca88c | |||
| ffa14c3aad | |||
| 41b32f0da4 | |||
| c53b2198a8 | |||
| 9b278db993 | |||
| e98f1a28e6 | |||
| c8f05b7c0c | |||
| b00c4a6a8f | |||
| 84e1fb2cee | |||
| b983ac548c | |||
| fb562ea708 | |||
| cdeeeafc3f | |||
| b9a2426e57 | |||
| 81037b3091 | |||
| fc3c76f946 | |||
| 3fa971a510 | |||
| 63a0395a79 | |||
| 191223bb3c | |||
| 6f0bad816e | |||
| 94af3c2887 | |||
| e5d0417a6c | |||
| c02bda2427 | |||
| 385d2a143c | |||
| 67c1b364c4 | |||
| f029b4beb1 | |||
| 9474c99795 | |||
| 3040361fac | |||
| 44caa96d50 | |||
| 1bea0f3772 | |||
| eb0775ad53 | |||
| 8fc9566a83 | |||
| 134c7db4d2 | |||
| a0e3a99dd1 | |||
| 0edda2bea7 | |||
| ff7f139fd7 | |||
| 84a7f222ff | |||
| d29423c24e | |||
| 86a606e716 | |||
| 1e97588e7b | |||
| 3ccc0b5aa6 | |||
| 5464a605b1 | |||
| 5519749aa4 | |||
| 4a70265bfb | |||
| de0d860880 | |||
| a13e2f4578 | |||
| 01b508f182 | |||
| 2a8fa8612d | |||
| e27046098b | |||
| ca8b148fdc | |||
| c1f5be24e2 | |||
| 6cdec65ca1 | |||
| 967afd8bbb | |||
| 0ae1812f90 | |||
| eb5523d5d3 | |||
| 3f4bbbec29 | |||
| 70bd220f34 | |||
| bd3596f012 | |||
| 66ce990e0b | |||
| 690666537c | |||
| 056ba1ed13 | |||
| 93a1f2bf61 | |||
| ac5f5a33e9 | |||
| 0829ac30f7 | |||
| 9d50a04905 | |||
| 1ca7da6914 | |||
| 56e050fbc9 | |||
| 70e48e39a4 | |||
| 2b0c04f27e | |||
| 1ddbe16d28 | |||
| 09c1128d9e | |||
| 588c52a854 | |||
| 86ec3bcb44 | |||
| 9fc606de48 | |||
| 7fbee88061 | |||
| b3be2cdf9d | |||
| ff6b76986a | |||
| 5c3624eb86 | |||
| 144e357fd2 | |||
| be22f0d1e1 | |||
| 34a048f7da | |||
| ffe953b43d | |||
| b8eacfc7b6 | |||
| f8452bf1fc | |||
| 20943a81c1 | |||
| 1c4e75e83f | |||
| 9cb9964c2d | |||
| 1f8f94276e | |||
| 0d7c89e84a | |||
| a5bdb4a8e8 | |||
| 521ed28632 | |||
| d6300314c0 | |||
| 27130259cc | |||
| b4fb295bb3 | |||
| f7e608628b | |||
| 605d66845a | |||
| 37ec3d7006 | |||
| 89eb351d2b | |||
| abaacfe78d | |||
| f9f4551e8d | |||
| daf005d1ab | |||
| ce1ee962f5 | |||
| d0e4edfb43 | |||
| 749e5067fb | |||
| 75dcaf6d8d | |||
| 00a0a1e95d | |||
| 7a4106077a | |||
| 9c8eaeb988 | |||
| 7ed28e8a84 | |||
| a3d53a6288 | |||
| 2127dc56b1 | |||
| e59e34d334 | |||
| 4fd97c3ba6 | |||
| 107c7a36d0 | |||
| dcf2c43863 | |||
| 0c25f7cdc5 | |||
| e5c243ee93 | |||
| e9b6a8fc9a | |||
| a27c00862c | |||
| a06f75b6fb | |||
| d88b052d2d | |||
| 615eccb6d1 | |||
| d3c65b6ba5 | |||
| 90415e4a6e | |||
| 7352c312e0 | |||
| 0befadde1d | |||
| aef8b25a8e | |||
| ae81117f70 | |||
| d6cb105d5f | |||
| b7b9a016d3 | |||
| 5ac36b5f25 | |||
| 22bcf1ba70 | |||
| 51c705edf1 | |||
| 708a1b0cd3 | |||
| 7ab591667a | |||
| e45401bfb4 | |||
| 6b652afb8e | |||
| 0a0db23b17 | |||
| 76b85c0622 | |||
| 6fa0679be9 | |||
| afea221d64 | |||
| b9ec2de4db | |||
| 3dfd53aee0 | |||
| b54fc8ff95 | |||
| 8745942255 | |||
| c7be30e0ea | |||
| 1baa47c78e | |||
| 0b33df4e9d | |||
| 4c40495742 | |||
| 824b97d250 | |||
| 5bbab05161 | |||
| 83558a1352 | |||
| cb183e968a | |||
| 27d56d0da4 | |||
| c663566cd5 | |||
| 13d052027f | |||
| 7076cf69e4 | |||
| 6ae8adaa45 | |||
| 15bbdb2030 | |||
| 48c9c1682c | |||
| d3c5143292 | |||
| 3949e2220f | |||
| 9ed4f95c1a | |||
| 8daecf7532 | |||
| 11d665c25a | |||
| 98a086b91b | |||
| f323a179d9 | |||
| c6f282d20b | |||
| ba49a9100d | |||
| 6fe77155b5 | |||
| 677e7ff642 | |||
| 682b5fa0d3 | |||
| ab00db2ebd | |||
| 0a0e8f36eb | |||
| bbe44b49bc | |||
| 25bec19b1f | |||
| 81f83d5780 | |||
| d2019e3e4d | |||
| 489e8dc592 | |||
| 3edb3d8d8c | |||
| a705a2e38b | |||
| 7dfbda58d9 | |||
| 9b88a38e54 | |||
| 16a494347c | |||
| ad0f11668b | |||
| 699cabeb1c | |||
| 7207f4b0c5 | |||
| 9c1b464c94 | |||
| 04a1e7d638 | |||
| 7cfbd87f57 | |||
| e9e05a3783 | |||
| 2b83f27f06 | |||
| 3d0e194298 | |||
| fcd8860990 | |||
| 22840ddf97 | |||
| f9576c2f5b | |||
| 16fc961010 | |||
| d2701d8b13 | |||
| a0bd31646b | |||
| 0d37da54b4 | |||
| 5d47e2a166 | |||
| 035c75d6a9 | |||
| b475481788 | |||
| 033525fe13 | |||
| 8852d090b6 | |||
| ac259ac790 | |||
| 7b4a87d37c | |||
| f6fc3ebe37 | |||
| 5c106abe3f | |||
| db748b7a05 | |||
| f2f2d532f5 | |||
| 1bcec3f769 | |||
| b035ee2bcd | |||
| 0424fb486b | |||
| 3858422f1d | |||
| d4f343751e | |||
| 79baddc157 | |||
| bcf437dc11 | |||
| 503eb470a7 | |||
| 667af1be58 | |||
| 366779f8c7 | |||
| dae299b781 | |||
| 2f29894b45 | |||
| 0819d05a0b | |||
| 6a4e44607c | |||
| a71daee545 | |||
| 046dd55032 | |||
| 2fc3da3fde | |||
| a74093784c | |||
| ed58374964 | |||
| 6dd4d1a924 | |||
| d77269dee2 | |||
| ea263b8cc5 | |||
| 45f0c812af | |||
| 810a1eee41 | |||
| e3e225d21b | |||
| 50e10ceb3b | |||
| da774e3fd2 | |||
| 2c3febd620 | |||
| bce62b98d4 | |||
| e914a8710d | |||
| c96e0afbf1 | |||
| f1c24f434b | |||
| e8517e1d02 | |||
| 92e406cef0 | |||
| 269913ede0 | |||
| 2ed16240a7 | |||
| ff36b754cb | |||
| 503b897677 | |||
| d69c74665a | |||
| fcf081283c | |||
| 7a6e8543a6 | |||
| f30755a871 | |||
| 503220e4c1 | |||
| 051814a69c | |||
| 21843da9e3 | |||
| 30f49f81c1 | |||
| 439f4776e4 | |||
| b743f56fb9 | |||
| 1fc3f6cb2e | |||
| df19c48da8 | |||
| f7211408fc | |||
| 30db316e16 | |||
| 8c01e952f3 | |||
| 3e66b88031 | |||
| f76316f889 | |||
| 32477a88ef | |||
| e8bc576b23 | |||
| 2eea6f2490 | |||
| 1d9d79542c | |||
| 1a6d4c955a | |||
| 717522efe4 | |||
| 8d06d9c23d | |||
| 765c1546c5 | |||
| 7ec6fd30f0 | |||
| 0ca773114a | |||
| 9e1576418f | |||
| b7ea169c81 | |||
| 3b583cbac7 | |||
| 382bd87667 | |||
| 6cc07dc24e | |||
| 01cdd22a01 | |||
| 35331e6973 | |||
| c18e98e8c5 | |||
| 3cd553565f | |||
| 9eec9f5788 | |||
| 2b7ca2bdd6 | |||
| 411c0add3b | |||
| 18d7ecc1a5 | |||
| 4812601e78 | |||
| 2d5779b660 | |||
| fd53e8b955 | |||
| 53a030c65b | |||
| 91ad6b42c5 | |||
| dad10ef800 | |||
| 71eb21aab7 | |||
| f8228e305a | |||
| 0e7109cab2 | |||
| c39ef1b25c | |||
| 9da37ed394 | |||
| 8fa571c283 | |||
| 83f3ae14d5 | |||
| 6a14c3edb4 | |||
| 2cd895c50b | |||
| ee89c0458f | |||
| cee847a68c | |||
| 413f96553a | |||
| 662ed4a67c | |||
| 85a263130d | |||
| d19ae37af1 | |||
| 22672a816e | |||
| dcb873c88d | |||
| 62ab2987b6 | |||
| 7bcde35651 | |||
| 4b8721a0bb | |||
| 7743e34596 | |||
| 4003b76fd3 | |||
| c27ed1896f | |||
| 7d217269b5 | |||
| a3c8882648 | |||
| 4389059834 | |||
| a55e90fefd | |||
| f58f922487 | |||
| 1a0930f841 | |||
| a5f8c3f692 | |||
| 92fb65cf2e | |||
| a51943e27f | |||
| 03c834e410 | |||
| 989107094c | |||
| fd8956b8f4 | |||
| 648e3c65ea | |||
| d5047e621d | |||
| 8fbdef01d6 | |||
| 9dee943fae | |||
| 8ceb691cec | |||
| f26516f6fa | |||
| fda8e8a30b | |||
| 2242178d96 | |||
| a459bc13dc | |||
| 53e84b7f31 | |||
| 098f51aa80 | |||
| 765969e6a3 | |||
| 8086c14dcc | |||
| 80ce1b7d85 | |||
| 9f55404845 | |||
| 075040ae05 | |||
| aa799d6a0d | |||
| 58e607e960 | |||
| ff51c5ee56 | |||
| 73c1f08776 | |||
| 412ca36230 | |||
| 06d1df4cae | |||
| 7662808bc9 | |||
| d48828dd80 | |||
| b725e01cdd | |||
| 874c1f076d | |||
| 2c14f0a109 | |||
| cf4afc2e7b | |||
| 5ed06f7eb8 | |||
| 765cd66b30 | |||
| 5a8fbc230d | |||
| 5c62211f00 | |||
| 835b8ffa22 | |||
| b84108c4b5 | |||
| 6642e1fc9d | |||
| c909e8e4b8 | |||
| 9bdbb45517 | |||
| 1b5860e574 | |||
| 047d45584e | |||
| 721486f875 | |||
| 29f2ecd228 | |||
| 970ac22647 | |||
| 419eab5059 | |||
| a1935bc1f4 | |||
| fc06c8ed9f | |||
| 7952b26e8b | |||
| fa6cfde4b0 | |||
| 4c78ba2152 | |||
| 9870e43ac0 | |||
| 63086c7eaf | |||
| ef0c6fc4b3 | |||
| 159c5311c3 | |||
| b6a65fac36 | |||
| ab7367ae47 | |||
| 457f509b5f | |||
| 7e5c063d98 | |||
| dfabd0e0ad | |||
| 141133e326 | |||
| e188a542da | |||
| 64f1e8b7a2 | |||
| 62440df051 | |||
| 5362e883f4 | |||
| 8b06fd0935 | |||
| bb9b58b8c4 | |||
| ee070c9bd3 | |||
| aebafdcd08 | |||
| 2b4fce8684 | |||
| de8f6709f7 | |||
| 683753db96 | |||
| d13dc7eca7 | |||
| e56920e445 | |||
| 1c9aad4d7b | |||
| 79fe30321a | |||
| 35ee7f3cba | |||
| 4c2e86b063 | |||
| d52a9b61af | |||
| 8a5b39f734 | |||
| ce09cb0bdb | |||
| b7fd91817e | |||
| a728047281 | |||
| 775c9648f9 | |||
| f65bdf5733 | |||
| 213d930f8c | |||
| fae025aac8 | |||
| 97477ee51c | |||
| 99894686cf | |||
| 1162e30768 | |||
| cd910b1512 | |||
| efa86ddf46 | |||
| d8f60cd7f2 | |||
| c4d19dfa92 | |||
| 35e70f4be1 | |||
| eb6c388f13 | |||
| 42144d957b | |||
| d1c778680b | |||
| 0fe006157e | |||
| 4d208dc092 | |||
| 162e86663f | |||
| 83ffb68bb7 | |||
| 4705321988 | |||
| 37a2356485 | |||
| 5cf473b31c | |||
| a7484f16cb | |||
| 6c8aad0afb | |||
| c767d55e9a | |||
| 7f601c9535 | |||
| 12cc7388e7 | |||
| 2ff61bdfc7 | |||
| eb0d7465e2 | |||
| 07d798c61a | |||
| b426e8577b | |||
| 532133d648 | |||
| c056a0d108 | |||
| 6fe1825db9 | |||
| b15968f140 | |||
| 0ddf1bf660 | |||
| dade5b5ef2 | |||
| 3aea9a7c20 | |||
| 0dce7769f4 | |||
| 4b73438833 | |||
| 8c3f01fbfa | |||
| b7abacfa7e | |||
| 3383e9c556 | |||
| 0380601bb4 | |||
| 4b4c2a2abd | |||
| b1542d4e98 | |||
| d469c2da48 | |||
| 29c5e390aa | |||
| 3455e5690c | |||
| 0ca8a5e186 | |||
| cb85d00e9e | |||
| 8ce1ce85ad | |||
| a6d3cbe824 | |||
| 9b9aa9c353 | |||
| 831620bfc4 | |||
| 4f50988799 | |||
| ff97a73152 | |||
| 769d8dd038 | |||
| 1d793ea338 | |||
| 5337413c56 | |||
| 380905618a | |||
| 3ff56e4405 | |||
| 58297774f7 | |||
| 5e9ff85fa8 | |||
| eb7a9c55b0 | |||
| 6157af56e9 | |||
| d6f84887ff | |||
| 729ffeee09 | |||
| 0092995f9d | |||
| 3fb69d59bb | |||
| cb207afdf3 | |||
| 756c1b7bcb | |||
| cd484979a8 | |||
| 9e3ea92829 | |||
| c37de9459e | |||
| 4d512c2cf6 | |||
| 81f10f53ad | |||
| fbf036a654 | |||
| 40bcfc7c8d | |||
| bfe0ffd6e6 | |||
| 8ee6bb5d4b | |||
| 0ebc2add03 | |||
| 7840c1b89f | |||
| 0428d5ae2e | |||
| b967ae2739 | |||
| c462496bd5 | |||
| a903e5024c | |||
| 7cce55e2fc | |||
| 99a1a10286 | |||
| 9640b49319 | |||
| 1bc0e66ed1 | |||
| 117d32dfc4 | |||
| 320b84df4f | |||
| 98eaf5c6c0 | |||
| 9842019205 | |||
| 479278be4e | |||
| 4767311a22 | |||
| f50fc33749 | |||
| 8aba92da9b | |||
| 59f3e10f0a | |||
| 8b82bcef7d | |||
| 1e595f2e26 | |||
| 28ad4f8623 | |||
| a3c04db828 | |||
| 3ea7af4c9c | |||
| 190c3ab0cd | |||
| 53c7cf895c | |||
| db1b7b2d21 | |||
| 7cd7886111 | |||
| 164ba944ac | |||
| e7fb2cf73b | |||
| 023cc8b572 | |||
| 0ff5ff6ff2 | |||
| a35d6a6f8d | |||
| 663b62e45f | |||
| 6910182011 | |||
| bba47b6f54 | |||
| ef372bd861 | |||
| fbbfe438dc | |||
| 7e495a5fe5 | |||
| 0f036eebc0 | |||
| e008eeac6a | |||
| 25e330500f | |||
| fa20988f51 | |||
| 99f4cc3006 | |||
| a1487e4814 | |||
| 183a02c584 | |||
| 913e8b2e02 | |||
| 5800e085e8 | |||
| 623d687192 | |||
| fcb668663b | |||
| ad98efe1fd | |||
| 3fae8b49db | |||
| 8fb9db3deb | |||
| 0859ccc5c0 | |||
| 0c9ddd51a4 | |||
| f77709e67e | |||
| 81e3b64ecd | |||
| 39728b8bfb | |||
| 3b5998af12 | |||
| eea19f8112 | |||
| 268fb22bca | |||
| 37e23a19b5 | |||
| 7d55bfc120 | |||
| ab1741ab38 | |||
| af76d26771 | |||
| d2097e9fdd | |||
| d325c36eb8 | |||
| 79b55d5e2b | |||
| 0c9aaed9f7 | |||
| 82d5f48fa7 | |||
| 2239e43faf | |||
| 70b0ade8c3 | |||
| 86b6d01242 | |||
| 826a3b3012 | |||
| 35d622c131 | |||
| 4bdd2ff93c | |||
| 6fffed179b | |||
| e6b91d3d7c | |||
| 99a7bf9faa | |||
| 44eb478437 | |||
| fc2cd3e1d5 | |||
| a5a9347308 | |||
| b6ed117726 | |||
| 4b23decb08 | |||
| a70ea6579d | |||
| cade30b117 | |||
| 1ca641f718 | |||
| 6222e7be78 | |||
| c7deff4d2e | |||
| 590615ba52 | |||
| b1dafcfe6d | |||
| 4998cf80c1 | |||
| 37e23133e9 | |||
| 91fd9c1ef2 | |||
| 12687a63f4 | |||
| d699d872d9 | |||
| fb2cbe471b | |||
| 17894add95 | |||
| 23d93f6846 | |||
| 2e3dd8dd0b | |||
| 426f02906b | |||
| 2d12ba3ac0 | |||
| 21335e6459 | |||
| 8421cb6d21 | |||
| cac72a9423 | |||
| 9266b81aff | |||
| 52475b1761 | |||
| 2f6347b924 | |||
| eb5456f9c7 | |||
| f914fd0219 | |||
| c94ca4c0cb | |||
| 31a192454c | |||
| 4b2246ba9f | |||
| 0ffffb12da | |||
| 4c857bf031 | |||
| 3f3f4fafff | |||
| 4367ae4acf | |||
| 4eafb0ce7f | |||
| 7a4891b6b9 | |||
| 0171c276f0 | |||
| 0743dd195d | |||
| d1a204a784 | |||
| c2809c2948 | |||
| 99e5a14703 | |||
| 0efc79bcb9 | |||
| 57dea0e4d8 | |||
| 706d0c3a91 | |||
| 1637de3ebb | |||
| 45691a4622 | |||
| 9e47c72b98 | |||
| f5d13dc568 | |||
| a36c1cd54a | |||
| 74458ab096 | |||
| c39b1a31db | |||
| 635c7fa153 | |||
| b7ac0a9e8d | |||
| 3f3ae4b2b6 | |||
| c2423dc07f | |||
| 1296630160 | |||
| 63eec25044 | |||
| 7a9b0731cf | |||
| d45661c405 | |||
| 002bec256a | |||
| 01e8668357 | |||
| 000861cba8 | |||
| 36473b2774 | |||
| 4188f50105 | |||
| 3e3b9ae2df | |||
| e89f0de232 | |||
| 4858e16a11 | |||
| 902a6db0e1 | |||
| 19ae6122c7 | |||
| b82b91ea08 | |||
| 636f0d7063 | |||
| ed73441a4c | |||
| 0f3cebd2b7 | |||
| 4c2be6cd49 | |||
| f3f51bd643 | |||
| 7479ac48e8 | |||
| d5f94d73ad | |||
| 4c5672119a | |||
| 8482f943ea | |||
| 15aaf7dfa0 | |||
| 768abf83f6 | |||
| ca76d53452 | |||
| b0904d6598 | |||
| b0a09f7b9e | |||
| eb4891bcc8 | |||
| 803fd8f037 | |||
| 67bdb5b1a3 | |||
| acc635b535 | |||
| 4e8ce87792 | |||
| 2c8daa25dc | |||
| 054ee0a8b5 | |||
| d0cadaf1a6 | |||
| 317db2758a | |||
| 25102d4792 | |||
| d39f1c461e | |||
| 7a6fc3a93b | |||
| 83c002c197 | |||
| fc47b5dee0 | |||
| 6c2e0b09ba | |||
| 3d4698debe | |||
| 4a25cfb27c | |||
| 294bd6a446 | |||
| d0109db23b | |||
| ee3ee66aae | |||
| f74e281efa | |||
| c0cd02883f | |||
| d9adb0fd6b | |||
| 6363013dd8 | |||
| 934131abf8 | |||
| 4e5337412a | |||
| 00f2e911a7 | |||
| c82d7d3d87 | |||
| ecfea027a0 | |||
| 96be494730 | |||
| 12c8db927b | |||
| 027ea587fc | |||
| 026900c7f0 | |||
| ffa87f55c4 | |||
| c9eed04b51 | |||
| b50b6b9f33 | |||
| 8fd5bef0bd | |||
| d6b49994a2 | |||
| 776927709b | |||
| 96e033b22c | |||
| 3469178dc1 | |||
| af1b3b6368 | |||
| d56789e5a7 | |||
| aeacf3a9d8 | |||
| 4ba486baa2 | |||
| f1ffd90294 | |||
| 777aa8b118 | |||
| cb9e16f4df | |||
| 2908923db9 | |||
| 8c1dfabb6b | |||
| 7fe36de069 | |||
| 27d556735a | |||
| b70d211f21 | |||
| b3e3b6c656 | |||
| 1734286252 | |||
| c8c076f970 | |||
| e40b3ad338 | |||
| afec321db2 | |||
| 6e9f9e6f3c | |||
| f504b200a9 | |||
| 82e840a0ca | |||
| 82765ca96e | |||
| 5387ec5f29 | |||
| f2908cbc5a | |||
| 5337b0b471 | |||
| e51afc3509 | |||
| 2c004dbcc9 | |||
| e128ed7d26 | |||
| 9064ebfe97 | |||
| 4f7bbe0e4a | |||
| 208f168564 | |||
| 737bccbd5e | |||
| 87094ef96c | |||
| f5431a046d | |||
| 5a9422b6bc | |||
| d30198c99a | |||
| 0c8d59dd20 | |||
| a460d140fe | |||
| 881d18ee88 | |||
| d73a4aa34b | |||
| 5c298c1501 | |||
| a83ca2120e | |||
| 81799f7f78 | |||
| 7973f7e750 | |||
| 3dc62a67e0 | |||
| 081e36c909 | |||
| 3a1d364f59 | |||
| e50648279d | |||
| 929af320da | |||
| 8e7c7eeeba | |||
| b739044e69 | |||
| 9e0107c9fc | |||
| 107e016508 | |||
| 22d16c20f8 | |||
| 697c839c84 | |||
| de8bd88d2a | |||
| 595efba747 | |||
| c041d15569 | |||
| 57b20e634b | |||
| e285796fc1 | |||
| a19494d3a7 | |||
| d2a362fd52 | |||
| 0f3562ef02 | |||
| 03f683f9e7 | |||
| cecadce86d | |||
| a7c3906003 | |||
| 70dc0c15fd | |||
| 9eeed9d5bd | |||
| a054c2934e | |||
| 38102f14c1 | |||
| 0997df4fcf | |||
| a5a56e061c | |||
| 8b007ad55a | |||
| 57dd5ec4db | |||
| 5b621d5be1 | |||
| 7aee762f3a | |||
| 4ee50c5a35 | |||
| 28f440dd9e | |||
| 43b78e51a4 | |||
| 84f9fb706b | |||
| 812823cad8 | |||
| 0655260378 | |||
| cfc3723879 | |||
| 4c3281b3f2 | |||
| ff94c605e0 | |||
| cb0a59bb2c | |||
| 076700bd22 | |||
| bcccc8338f | |||
| 425dec8bb8 | |||
| 838554460b | |||
| 659c3c528d | |||
| 60aeab3c38 | |||
| 5e3cf45df3 | |||
| 4633591918 | |||
| 0e6a8b7c72 | |||
| 147848ca20 | |||
| cde002c579 | |||
| f23d93ba89 | |||
| c97a8418dc | |||
| 4aca9372a6 | |||
| 4912ecc3ea | |||
| c1c8ceafc2 | |||
| 9c0a3b6c60 | |||
| 7b539e3025 | |||
| b2b0043875 | |||
| 53e0d182af | |||
| a6fa41e290 | |||
| edba99d636 | |||
| 35674959f2 | |||
| dc8b7a0eb8 | |||
| 8d1f46d837 | |||
| a2117d23b2 | |||
| a58e4d0359 | |||
| 576914aee1 | |||
| 8171f8209a | |||
| 64ff05303c | |||
| 6caab6225d | |||
| 326411498a | |||
| d50fcf0020 | |||
| d354d36a3b | |||
| 483a72ac61 | |||
| dbec4b0d0e | |||
| 4cb489b9e4 | |||
| 28ec50d567 | |||
| 73beed0477 | |||
| e0ecdd4b24 | |||
| 0cb1a578d0 | |||
| 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 | |||
| 02a8bba02e | |||
| 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 | |||
| e139d1cbe4 | |||
| cb04116caf | |||
| 62ff8daa78 | |||
| a315e7c962 | |||
| 42364f2fce | |||
| 8f600798ef | |||
| f28c268d97 | |||
| f1cff20249 | |||
| 865d88dd56 | |||
| 069c05669f | |||
| 516065d7c2 | |||
| 6ea68869c9 |
@@ -0,0 +1,10 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
end_of_line = lf
|
||||
|
||||
[*.y{,a}ml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
tab_width = 2
|
||||
+32
-30
@@ -1,5 +1,5 @@
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -38,10 +38,10 @@ jobs:
|
||||
cd tests/vendor
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Odin issues tests
|
||||
- name: Odin internals tests
|
||||
run: |
|
||||
cd tests/issues
|
||||
./run.sh
|
||||
cd tests/internal
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for Linux i386
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
||||
@@ -58,8 +58,8 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM, botan and setup PATH
|
||||
run: |
|
||||
brew install llvm@11 botan
|
||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||
brew install llvm@13 botan
|
||||
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
@@ -87,16 +87,11 @@ jobs:
|
||||
cd tests/core
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Vendor library tests
|
||||
- name: Odin internals tests
|
||||
run: |
|
||||
cd tests/vendor
|
||||
cd tests/internal
|
||||
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
|
||||
@@ -104,13 +99,13 @@ jobs:
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
||||
timeout-minutes: 10
|
||||
build_windows:
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
./build.bat 1
|
||||
- name: Odin version
|
||||
run: ./odin version
|
||||
@@ -121,58 +116,65 @@ jobs:
|
||||
- name: Odin check
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
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
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
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
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\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
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
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
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\vendor
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: Odin internals tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\internal
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: Odin documentation tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\documentation
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: core:math/big tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
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
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style -target:windows_i386
|
||||
timeout-minutes: 10
|
||||
|
||||
@@ -7,24 +7,26 @@ on:
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-2019
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
./build.bat 1 1
|
||||
- name: Odin run
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo
|
||||
- name: Copy artifacts
|
||||
run: |
|
||||
rm bin/llvm/windows/LLVM-C.lib
|
||||
mkdir dist
|
||||
cp odin.exe dist
|
||||
cp LICENSE dist
|
||||
cp LLVM-C.dll dist
|
||||
cp -r shared dist
|
||||
cp -r core dist
|
||||
@@ -37,6 +39,7 @@ jobs:
|
||||
name: windows_artifacts
|
||||
path: dist
|
||||
build_ubuntu:
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@@ -50,6 +53,8 @@ jobs:
|
||||
run: |
|
||||
mkdir dist
|
||||
cp odin dist
|
||||
cp LICENSE dist
|
||||
cp libLLVM* dist
|
||||
cp -r shared dist
|
||||
cp -r core dist
|
||||
cp -r vendor dist
|
||||
@@ -60,13 +65,14 @@ jobs:
|
||||
name: ubuntu_artifacts
|
||||
path: dist
|
||||
build_macos:
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM and setup PATH
|
||||
run: |
|
||||
brew install llvm@11
|
||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||
brew install llvm@13
|
||||
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
@@ -77,6 +83,7 @@ jobs:
|
||||
run: |
|
||||
mkdir dist
|
||||
cp odin dist
|
||||
cp LICENSE dist
|
||||
cp -r shared dist
|
||||
cp -r core dist
|
||||
cp -r vendor dist
|
||||
|
||||
@@ -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@v7.0.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: -1
|
||||
exempt-draft-pr: true
|
||||
ascending: true
|
||||
operations-per-run: 1000
|
||||
exempt-issue-labels: "ignore"
|
||||
+29
@@ -22,6 +22,32 @@ bld/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
![Cc]ore/[Ll]og/
|
||||
tests/documentation/verify/
|
||||
tests/documentation/all.odin-doc
|
||||
tests/internal/test_map
|
||||
tests/internal/test_pow
|
||||
tests/internal/test_rtti
|
||||
tests/core/test_core_compress
|
||||
tests/core/test_core_filepath
|
||||
tests/core/test_core_fmt
|
||||
tests/core/test_core_i18n
|
||||
tests/core/test_core_image
|
||||
tests/core/test_core_libc
|
||||
tests/core/test_core_match
|
||||
tests/core/test_core_math
|
||||
tests/core/test_core_net
|
||||
tests/core/test_core_os_exit
|
||||
tests/core/test_core_reflect
|
||||
tests/core/test_core_strings
|
||||
tests/core/test_crypto_hash
|
||||
tests/core/test_hash
|
||||
tests/core/test_hxa
|
||||
tests/core/test_json
|
||||
tests/core/test_linalg_glsl_math
|
||||
tests/core/test_noise
|
||||
tests/core/test_varint
|
||||
tests/core/test_xml
|
||||
tests/vendor/vendor_botan
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Visual Studio Code options directory
|
||||
@@ -268,9 +294,11 @@ bin/
|
||||
|
||||
# - Linux/MacOS
|
||||
odin
|
||||
!odin/
|
||||
odin.dSYM
|
||||
*.bin
|
||||
demo.bin
|
||||
libLLVM*.so*
|
||||
|
||||
# shared collection
|
||||
shared/
|
||||
@@ -283,3 +311,4 @@ shared/
|
||||
*.sublime-workspace
|
||||
examples/bug/
|
||||
build.sh
|
||||
!core/debug/
|
||||
|
||||
BIN
Binary file not shown.
@@ -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/odinlang">
|
||||
<a href="https://discord.com/invite/sVBPHEv">
|
||||
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
|
||||
</a>
|
||||
<a href="https://github.com/odin-lang/odin/actions">
|
||||
@@ -82,7 +82,7 @@ A wiki maintained by the Odin community.
|
||||
|
||||
#### [Odin Discord](https://discord.gg/sVBPHEv)
|
||||
|
||||
Get live support and talk with other odiners on the Odin Discord.
|
||||
Get live support and talk with other Odin programmers on the Odin Discord.
|
||||
|
||||
### Articles
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -2,6 +2,23 @@
|
||||
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
where /Q cl.exe || (
|
||||
set __VSCMD_ARG_NO_LOGO=1
|
||||
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
|
||||
if "!VS!" equ "" (
|
||||
echo ERROR: Visual Studio installation not found
|
||||
exit /b 1
|
||||
)
|
||||
call "!VS!\VC\Auxiliary\Build\vcvarsall.bat" amd64 || exit /b 1
|
||||
)
|
||||
|
||||
if "%VSCMD_ARG_TGT_ARCH%" neq "x64" (
|
||||
if "%ODIN_IGNORE_MSVC_CHECK%" == "" (
|
||||
echo ERROR: please run this from MSVC x64 native tools command prompt, 32-bit target is not supported!
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
for /f "usebackq tokens=1,2 delims=,=- " %%i in (`wmic os get LocalDateTime /value`) do @if %%i==LocalDateTime (
|
||||
set CURR_DATE_TIME=%%j
|
||||
)
|
||||
@@ -33,8 +50,14 @@ set odin_version_raw="dev-%curr_year%-%curr_month%"
|
||||
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF
|
||||
set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\"
|
||||
|
||||
for /f %%i in ('git rev-parse --short HEAD') do set GIT_SHA=%%i
|
||||
if not exist .git\ goto skip_git_hash
|
||||
for /f "tokens=1,2" %%i IN ('git show "--pretty=%%cd %%h" "--date=format:%%Y-%%m" --no-patch --no-notes HEAD') do (
|
||||
set odin_version_raw=dev-%%i
|
||||
set GIT_SHA=%%j
|
||||
)
|
||||
if %ERRORLEVEL% equ 0 set compiler_defines=%compiler_defines% -DGIT_SHA=\"%GIT_SHA%\"
|
||||
:skip_git_hash
|
||||
|
||||
if %nightly% equ 1 set compiler_defines=%compiler_defines% -DNIGHTLY
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
@@ -47,18 +70,30 @@ if %release_mode% EQU 0 ( rem Debug
|
||||
set compiler_warnings= ^
|
||||
-W4 -WX ^
|
||||
-wd4100 -wd4101 -wd4127 -wd4146 ^
|
||||
-wd4505 ^
|
||||
-wd4456 -wd4457
|
||||
|
||||
set compiler_includes= ^
|
||||
/Isrc\
|
||||
set libs= ^
|
||||
kernel32.lib ^
|
||||
Synchronization.lib ^
|
||||
bin\llvm\windows\LLVM-C.lib
|
||||
|
||||
rem DO NOT TOUCH!
|
||||
rem THIS TILDE STUFF IS FOR DEVELOPMENT ONLY!
|
||||
set tilde_backend=0
|
||||
if %tilde_backend% EQU 1 (
|
||||
set libs=%libs% src\tilde\tb.lib
|
||||
set compiler_defines=%compiler_defines% -DODIN_TILDE_BACKEND
|
||||
)
|
||||
rem DO NOT TOUCH!
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
@@ -75,7 +110,8 @@ if %errorlevel% neq 0 goto end_of_build
|
||||
call build_vendor.bat
|
||||
if %errorlevel% neq 0 goto end_of_build
|
||||
|
||||
if %release_mode% EQU 0 odin run examples/demo
|
||||
rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native
|
||||
if %release_mode% EQU 0 odin run examples/demo -- Hellope World
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
|
||||
+88
-97
@@ -1,82 +1,92 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
GIT_SHA=$(git rev-parse --short HEAD)
|
||||
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
|
||||
LDFLAGS="-pthread -lm -lstdc++"
|
||||
CFLAGS="-std=c++14 -DGIT_SHA=\"$GIT_SHA\""
|
||||
CFLAGS="$CFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
|
||||
CC=clang
|
||||
OS=$(uname)
|
||||
: ${CPPFLAGS=}
|
||||
: ${CXX=clang++}
|
||||
: ${CXXFLAGS=}
|
||||
: ${LDFLAGS=}
|
||||
: ${LLVM_CONFIG=}
|
||||
|
||||
panic() {
|
||||
printf "%s\n" "$1"
|
||||
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
|
||||
CXXFLAGS="$CXXFLAGS -std=c++14"
|
||||
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
|
||||
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
|
||||
OS_ARCH="$(uname -m)"
|
||||
OS_NAME="$(uname -s)"
|
||||
|
||||
if [ -d ".git" ] && [ -n "$(command -v git)" ]; then
|
||||
GIT_SHA=$(git show --pretty='%h' --no-patch --no-notes HEAD)
|
||||
CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\""
|
||||
fi
|
||||
|
||||
error() {
|
||||
printf "ERROR: %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")
|
||||
if [ -z "$LLVM_CONFIG" ]; then
|
||||
# darwin, linux, openbsd
|
||||
if [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17"
|
||||
elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14"
|
||||
elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13"
|
||||
elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12"
|
||||
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
|
||||
# freebsd
|
||||
elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config-17"
|
||||
elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config-14"
|
||||
elif [ -n "$(command -v llvm-config13)" ]; then LLVM_CONFIG="llvm-config-13"
|
||||
elif [ -n "$(command -v llvm-config12)" ]; then LLVM_CONFIG="llvm-config-12"
|
||||
elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11"
|
||||
# fallback
|
||||
elif [ -n "$(command -v llvm-config)" ]; then LLVM_CONFIG="llvm-config"
|
||||
else
|
||||
# allow for x86 / amd64 all llvm versions begining from 11
|
||||
MIN_LLVM_VERSION=("11.1.0")
|
||||
error "No llvm-config command found. Set LLVM_CONFIG to proceed."
|
||||
fi
|
||||
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"
|
||||
LLVM_VERSION="$($LLVM_CONFIG --version)"
|
||||
LLVM_VERSION_MAJOR="$(echo $LLVM_VERSION | awk -F. '{print $1}')"
|
||||
LLVM_VERSION_MINOR="$(echo $LLVM_VERSION | awk -F. '{print $2}')"
|
||||
LLVM_VERSION_PATCH="$(echo $LLVM_VERSION | awk -F. '{print $3}')"
|
||||
|
||||
if [ $LLVM_VERSION_MAJOR -lt 11 ] ||
|
||||
([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]); then
|
||||
error "Invalid LLVM version $LLVM_VERSION: must be 11, 12, 13, 14 or 17"
|
||||
fi
|
||||
|
||||
case "$OS_NAME" in
|
||||
Darwin)
|
||||
if [ "$OS_ARCH" == "arm64" ]; then
|
||||
if [ $LLVM_VERSION_MAJOR -lt 13 ] || [ $LLVM_VERSION_MAJOR -gt 17 ]; then
|
||||
error "Darwin Arm64 requires LLVM 13, 14 or 17"
|
||||
fi
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl -framework System"
|
||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||
}
|
||||
|
||||
config_freebsd() {
|
||||
LLVM_CONFIG=/usr/local/bin/llvm-config11
|
||||
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
;;
|
||||
FreeBSD)
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
config_openbsd() {
|
||||
LLVM_CONFIG=/usr/local/bin/llvm-config
|
||||
|
||||
;;
|
||||
Linux)
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -ldl $($LLVM_CONFIG --libs core native --system-libs --libfiles)"
|
||||
# Copy libLLVM*.so into current directory for linking
|
||||
# NOTE: This is needed by the Linux release pipeline!
|
||||
cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./
|
||||
LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN"
|
||||
;;
|
||||
OpenBSD)
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -liconv"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
config_linux() {
|
||||
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
|
||||
|
||||
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"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
;;
|
||||
*)
|
||||
error "Platform \"$OS_NAME\" unsupported"
|
||||
;;
|
||||
esac
|
||||
|
||||
build_odin() {
|
||||
case $1 in
|
||||
@@ -87,64 +97,45 @@ build_odin() {
|
||||
EXTRAFLAGS="-O3"
|
||||
;;
|
||||
release-native)
|
||||
EXTRAFLAGS="-O3 -march=native"
|
||||
if [ "$OS_ARCH" == "arm64" ]; then
|
||||
# Use preferred flag for Arm (ie arm64 / aarch64 / etc)
|
||||
EXTRAFLAGS="-O3 -mcpu=native"
|
||||
else
|
||||
# Use preferred flag for x86 / amd64
|
||||
EXTRAFLAGS="-O3 -march=native"
|
||||
fi
|
||||
;;
|
||||
nightly)
|
||||
EXTRAFLAGS="-DNIGHTLY -O3"
|
||||
;;
|
||||
*)
|
||||
panic "Build mode unsupported!"
|
||||
error "Build mode \"$1\" unsupported!"
|
||||
;;
|
||||
esac
|
||||
|
||||
set -x
|
||||
$CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||
$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
|
||||
./odin run examples/demo/demo.odin -file -- Hellope World
|
||||
}
|
||||
|
||||
case $OS in
|
||||
Linux)
|
||||
config_linux
|
||||
;;
|
||||
Darwin)
|
||||
config_darwin
|
||||
;;
|
||||
OpenBSD)
|
||||
config_openbsd
|
||||
;;
|
||||
FreeBSD)
|
||||
config_freebsd
|
||||
;;
|
||||
*)
|
||||
panic "Platform unsupported!"
|
||||
esac
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
if [ $# -eq 0 ]; then
|
||||
build_odin debug
|
||||
run_demo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
elif [ $# -eq 1 ]; then
|
||||
case $1 in
|
||||
report)
|
||||
if [[ ! -f "./odin" ]]; then
|
||||
build_odin debug
|
||||
fi
|
||||
|
||||
[ ! -f "./odin" ] && build_odin debug
|
||||
./odin report
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
build_odin $1
|
||||
;;
|
||||
esac
|
||||
|
||||
run_demo
|
||||
exit 0
|
||||
else
|
||||
panic "Too many arguments!"
|
||||
error "Too many arguments!"
|
||||
fi
|
||||
|
||||
@@ -15,3 +15,10 @@ if not exist "vendor\miniaudio\lib\*.lib" (
|
||||
call build.bat
|
||||
popd
|
||||
)
|
||||
|
||||
|
||||
if not exist "vendor\cgltf\lib\*.lib" (
|
||||
pushd vendor\cgltf\src
|
||||
call build.bat
|
||||
popd
|
||||
)
|
||||
|
||||
@@ -2,25 +2,25 @@ package bufio
|
||||
|
||||
import "core:io"
|
||||
|
||||
// Loadahead_Reader provides io lookahead.
|
||||
// Lookahead_Reader provides io lookahead.
|
||||
// This is useful for tokenizers/parsers.
|
||||
// Loadahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Loadahead_Reader's buffer size
|
||||
// Lookahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Lookahead_Reader's buffer size
|
||||
// will EXACTLY match the specified size, whereas bufio.Reader's buffer size may differ from the specified size.
|
||||
// This makes sure that the buffer will not be accidentally read beyond the expected size.
|
||||
Loadahead_Reader :: struct {
|
||||
Lookahead_Reader :: struct {
|
||||
r: io.Reader,
|
||||
buf: []byte,
|
||||
n: int,
|
||||
}
|
||||
|
||||
lookahead_reader_init :: proc(lr: ^Loadahead_Reader, r: io.Reader, buf: []byte) -> ^Loadahead_Reader {
|
||||
lookahead_reader_init :: proc(lr: ^Lookahead_Reader, r: io.Reader, buf: []byte) -> ^Lookahead_Reader {
|
||||
lr.r = r
|
||||
lr.buf = buf
|
||||
lr.n = 0
|
||||
return lr
|
||||
}
|
||||
|
||||
lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
|
||||
lookahead_reader_buffer :: proc(lr: ^Lookahead_Reader) -> []byte {
|
||||
return lr.buf[:lr.n]
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
|
||||
// lookahead_reader_peek returns a slice of the Lookahead_Reader which holds n bytes
|
||||
// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
|
||||
// NOTE: The returned buffer is not a copy of the underlying buffer
|
||||
lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Error) {
|
||||
lookahead_reader_peek :: proc(lr: ^Lookahead_Reader, n: int) -> ([]byte, io.Error) {
|
||||
switch {
|
||||
case n < 0:
|
||||
return nil, .Negative_Read
|
||||
@@ -58,13 +58,13 @@ lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Erro
|
||||
// lookahead_reader_peek_all returns a slice of the Lookahead_Reader populating the full buffer
|
||||
// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
|
||||
// NOTE: The returned buffer is not a copy of the underlying buffer
|
||||
lookahead_reader_peek_all :: proc(lr: ^Loadahead_Reader) -> ([]byte, io.Error) {
|
||||
lookahead_reader_peek_all :: proc(lr: ^Lookahead_Reader) -> ([]byte, io.Error) {
|
||||
return lookahead_reader_peek(lr, len(lr.buf))
|
||||
}
|
||||
|
||||
|
||||
// lookahead_reader_consume drops the first n populated bytes from the Lookahead_Reader.
|
||||
lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
|
||||
lookahead_reader_consume :: proc(lr: ^Lookahead_Reader, n: int) -> io.Error {
|
||||
switch {
|
||||
case n == 0:
|
||||
return nil
|
||||
@@ -78,6 +78,6 @@ lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
lookahead_reader_consume_all :: proc(lr: ^Loadahead_Reader) -> io.Error {
|
||||
lookahead_reader_consume_all :: proc(lr: ^Lookahead_Reader) -> io.Error {
|
||||
return lookahead_reader_consume(lr, lr.n)
|
||||
}
|
||||
|
||||
+22
-48
@@ -14,55 +14,29 @@ read_writer_init :: proc(rw: ^Read_Writer, r: ^Reader, w: ^Writer) {
|
||||
}
|
||||
|
||||
read_writer_to_stream :: proc(rw: ^Read_Writer) -> (s: io.Stream) {
|
||||
s.stream_data = rw
|
||||
s.stream_vtable = _read_writer_vtable
|
||||
s.procedure = _read_writer_procedure
|
||||
s.data = rw
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
_read_writer_vtable := &io.Stream_VTable{
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_read(b, p)
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_read_byte(b)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_unread_byte(b)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_read_rune(b)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_unread_rune(b)
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_write_to(b, w)
|
||||
},
|
||||
impl_flush = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_flush(b)
|
||||
},
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_write(b, p)
|
||||
},
|
||||
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_write_byte(b, c)
|
||||
},
|
||||
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_write_rune(b, r)
|
||||
},
|
||||
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_read_from(b, r)
|
||||
},
|
||||
}
|
||||
_read_writer_procedure := proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
rw := (^Read_Writer)(stream_data)
|
||||
n_int: int
|
||||
#partial switch mode {
|
||||
case .Flush:
|
||||
err = writer_flush(rw.w)
|
||||
return
|
||||
case .Read:
|
||||
n_int, err = reader_read(rw.r, p)
|
||||
n = i64(n_int)
|
||||
return
|
||||
case .Write:
|
||||
n_int, err = writer_write(rw.w, p)
|
||||
n = i64(n_int)
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Flush, .Read, .Write, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
+26
-76
@@ -118,9 +118,7 @@ reader_peek :: proc(b: ^Reader, n: int) -> (data: []byte, err: io.Error) {
|
||||
b.last_rune_size = -1
|
||||
|
||||
for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
|
||||
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
|
||||
return nil, fill_err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
if n > len(b.buf) {
|
||||
@@ -156,9 +154,7 @@ reader_discard :: proc(b: ^Reader, n: int) -> (discarded: int, err: io.Error) {
|
||||
for {
|
||||
skip := reader_buffered(b)
|
||||
if skip == 0 {
|
||||
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
|
||||
return 0, fill_err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
skip = reader_buffered(b)
|
||||
}
|
||||
skip = min(skip, remaining)
|
||||
@@ -223,20 +219,18 @@ reader_read :: proc(b: ^Reader, p: []byte) -> (n: int, err: io.Error) {
|
||||
|
||||
// reader_read_byte reads and returns a single byte
|
||||
// If no byte is available, it return an error
|
||||
reader_read_byte :: proc(b: ^Reader) -> (byte, io.Error) {
|
||||
reader_read_byte :: proc(b: ^Reader) -> (c: byte, err: io.Error) {
|
||||
b.last_rune_size = -1
|
||||
for b.r == b.w {
|
||||
if b.err != nil {
|
||||
return 0, _reader_consume_err(b)
|
||||
}
|
||||
if err := _reader_read_new_chunk(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
c := b.buf[b.r]
|
||||
c = b.buf[b.r]
|
||||
b.r += 1
|
||||
b.last_byte = int(c)
|
||||
return c, nil
|
||||
return
|
||||
}
|
||||
|
||||
// reader_unread_byte unreads the last byte. Only the most recently read byte can be unread
|
||||
@@ -264,15 +258,12 @@ reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) {
|
||||
!utf8.full_rune(b.buf[b.r:b.w]) &&
|
||||
b.err == nil &&
|
||||
b.w-b.w < len(b.buf) {
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
b.last_rune_size = -1
|
||||
if b.r == b.w {
|
||||
err = _reader_consume_err(b)
|
||||
return
|
||||
return 0, 0, _reader_consume_err(b)
|
||||
}
|
||||
r, size = rune(b.buf[b.r]), 1
|
||||
if r >= utf8.RUNE_SELF {
|
||||
@@ -305,39 +296,20 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
return i64(n), err
|
||||
}
|
||||
|
||||
n, err = write_buf(b, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n = write_buf(b, w) or_return
|
||||
|
||||
m: i64
|
||||
if nr, ok := io.to_writer_to(b.rd); ok {
|
||||
m, err = io.write_to(nr, w)
|
||||
n += m
|
||||
return n, err
|
||||
}
|
||||
|
||||
if nw, ok := io.to_reader_from(w); ok {
|
||||
m, err = io.read_from(nw, b.rd)
|
||||
n += m
|
||||
return n, err
|
||||
}
|
||||
|
||||
if b.w-b.r < len(b.buf) {
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
for b.r < b.w {
|
||||
m, err = write_buf(b, w)
|
||||
n += m
|
||||
n += m // this needs to be done before returning
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
if b.err == .EOF {
|
||||
@@ -352,48 +324,28 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
|
||||
// reader_to_stream converts a Reader into an io.Stream
|
||||
reader_to_stream :: proc(b: ^Reader) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = _reader_vtable
|
||||
s.data = b
|
||||
s.procedure = _reader_proc
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_reader_vtable := &io.Stream_VTable{
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Reader)(s.stream_data)
|
||||
_reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
b := (^Reader)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
return io._i64_err(reader_read(b, p))
|
||||
case .Destroy:
|
||||
reader_destroy(b)
|
||||
return nil
|
||||
},
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_read(b, p)
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_read_byte(b)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_unread_byte(b)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_read_rune(b)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_unread_rune(b)
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_write_to(b, w)
|
||||
},
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Read, .Destroy, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Utility procedures
|
||||
//
|
||||
@@ -435,9 +387,7 @@ reader_read_slice :: proc(b: ^Reader, delim: byte) -> (line: []byte, err: io.Err
|
||||
|
||||
s = b.w - b.r
|
||||
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
break
|
||||
}
|
||||
_reader_read_new_chunk(b) or_break
|
||||
}
|
||||
|
||||
if i := len(line)-1; i >= 0 {
|
||||
|
||||
@@ -66,7 +66,7 @@ scanner_destroy :: proc(s: ^Scanner) {
|
||||
}
|
||||
|
||||
|
||||
// Returns the first non-EOF error that was encounted by the scanner
|
||||
// Returns the first non-EOF error that was encountered by the scanner
|
||||
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
|
||||
switch s._err {
|
||||
case .EOF, nil:
|
||||
|
||||
+25
-36
@@ -159,7 +159,7 @@ writer_write_rune :: proc(b: ^Writer, r: rune) -> (size: int, err: io.Error) {
|
||||
return
|
||||
}
|
||||
|
||||
// writer_write writes a string into the buffer
|
||||
// writer_write_string writes a string into the buffer
|
||||
// It returns the number of bytes written
|
||||
// If n < len(p), it will return an error explaining why the write is short
|
||||
writer_write_string :: proc(b: ^Writer, s: string) -> (int, io.Error) {
|
||||
@@ -173,14 +173,6 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
if b.err != nil {
|
||||
return 0, b.err
|
||||
}
|
||||
if writer_buffered(b) == 0 {
|
||||
if w, ok := io.to_reader_from(b.wr); !ok {
|
||||
n, err = io.read_from(w, r)
|
||||
b.err = err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
if writer_available(b) == 0 {
|
||||
writer_flush(b) or_return
|
||||
@@ -222,38 +214,35 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
|
||||
// writer_to_stream converts a Writer into an io.Stream
|
||||
writer_to_stream :: proc(b: ^Writer) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = _writer_vtable
|
||||
s.data = b
|
||||
s.procedure = _writer_proc
|
||||
return
|
||||
}
|
||||
|
||||
// writer_to_stream converts a Writer into an io.Stream
|
||||
writer_to_writer :: proc(b: ^Writer) -> (s: io.Writer) {
|
||||
return writer_to_stream(b)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_writer_vtable := &io.Stream_VTable{
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Writer)(s.stream_data)
|
||||
_writer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
b := (^Writer)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Flush:
|
||||
err = writer_flush(b)
|
||||
return
|
||||
case .Write:
|
||||
n_int: int
|
||||
n_int, err = writer_write(b, p)
|
||||
n = i64(n_int)
|
||||
return
|
||||
case .Destroy:
|
||||
writer_destroy(b)
|
||||
return nil
|
||||
},
|
||||
impl_flush = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_flush(b)
|
||||
},
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_write(b, p)
|
||||
},
|
||||
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_write_byte(b, c)
|
||||
},
|
||||
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_write_rune(b, r)
|
||||
},
|
||||
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_read_from(b, r)
|
||||
},
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Flush, .Write, .Destroy, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
@@ -94,7 +94,15 @@ cap :: proc(array: Array_Type) -> int ---
|
||||
|
||||
size_of :: proc($T: typeid) -> int ---
|
||||
align_of :: proc($T: typeid) -> int ---
|
||||
offset_of :: proc($T: typeid) -> uintptr ---
|
||||
|
||||
// e.g. offset_of(t.f), where t is an instance of the type T
|
||||
offset_of_selector :: proc(selector: $T) -> uintptr ---
|
||||
// e.g. offset_of(T, f), where T can be the type instead of a variable
|
||||
offset_of_member :: proc($T: typeid, member: $M) -> uintptr ---
|
||||
offset_of :: proc{offset_of_selector, offset_of_member}
|
||||
// e.g. offset_of(T, "f"), where T can be the type instead of a variable
|
||||
offset_of_by_string :: proc($T: typeid, member: string) -> uintptr ---
|
||||
|
||||
type_of :: proc(x: expr) -> type ---
|
||||
type_info_of :: proc($T: typeid) -> ^runtime.Type_Info ---
|
||||
typeid_of :: proc($T: typeid) -> typeid ---
|
||||
@@ -109,7 +117,7 @@ jmag :: proc(value: Quaternion) -> Float ---
|
||||
kmag :: proc(value: Quaternion) -> Float ---
|
||||
conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion ---
|
||||
|
||||
expand_to_tuple :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
expand_values :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
|
||||
min :: proc(values: ..T) -> T ---
|
||||
max :: proc(values: ..T) -> T ---
|
||||
|
||||
+41
-66
@@ -38,6 +38,11 @@ buffer_init_string :: proc(b: ^Buffer, s: string) {
|
||||
}
|
||||
|
||||
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
|
||||
if b.buf == nil {
|
||||
b.buf = make([dynamic]byte, len, cap, allocator)
|
||||
return
|
||||
}
|
||||
|
||||
b.buf.allocator = allocator
|
||||
reserve(&b.buf, cap)
|
||||
resize(&b.buf, len)
|
||||
@@ -108,8 +113,11 @@ _buffer_grow :: proc(b: ^Buffer, n: int) -> int {
|
||||
if i, ok := _buffer_try_grow(b, n); ok {
|
||||
return i
|
||||
}
|
||||
|
||||
if b.buf == nil && n <= SMALL_BUFFER_SIZE {
|
||||
b.buf = make([dynamic]byte, n, SMALL_BUFFER_SIZE)
|
||||
// Fixes #2756 by preserving allocator if already set on Buffer via init_buffer_allocator
|
||||
reserve(&b.buf, SMALL_BUFFER_SIZE)
|
||||
resize(&b.buf, n)
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -161,6 +169,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,17 +241,18 @@ 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
|
||||
|
||||
if offset < 0 || offset >= len(b.buf) {
|
||||
if uint(offset) >= len(b.buf) {
|
||||
err = .Invalid_Offset
|
||||
return
|
||||
}
|
||||
|
||||
if 0 <= offset && offset < len(b.buf) {
|
||||
n = copy(p, b.buf[offset:])
|
||||
}
|
||||
n = copy(p, b.buf[offset:])
|
||||
if n > 0 {
|
||||
b.last_read = .Read
|
||||
}
|
||||
@@ -365,69 +378,31 @@ buffer_read_from :: proc(b: ^Buffer, r: io.Reader) -> (n: i64, err: io.Error) #n
|
||||
|
||||
|
||||
buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = _buffer_vtable
|
||||
s.data = b
|
||||
s.procedure = _buffer_proc
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
_buffer_vtable := &io.Stream_VTable{
|
||||
impl_size = proc(s: io.Stream) -> i64 {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return i64(buffer_capacity(b))
|
||||
},
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read(b, p)
|
||||
},
|
||||
impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_at(b, p, int(offset))
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_byte(b)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_rune(b)
|
||||
},
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write(b, p)
|
||||
},
|
||||
impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_at(b, p, int(offset))
|
||||
},
|
||||
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_byte(b, c)
|
||||
},
|
||||
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_rune(b, r)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_unread_byte(b)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_unread_rune(b)
|
||||
},
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
_buffer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
b := (^Buffer)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
return io._i64_err(buffer_read(b, p))
|
||||
case .Read_At:
|
||||
return io._i64_err(buffer_read_at(b, p, int(offset)))
|
||||
case .Write:
|
||||
return io._i64_err(buffer_write(b, p))
|
||||
case .Write_At:
|
||||
return io._i64_err(buffer_write_at(b, p, int(offset)))
|
||||
case .Size:
|
||||
n = i64(buffer_capacity(b))
|
||||
return
|
||||
case .Destroy:
|
||||
buffer_destroy(b)
|
||||
return nil
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_to(b, w)
|
||||
},
|
||||
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_from(b, r)
|
||||
},
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Size, .Destroy})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
|
||||
@@ -638,7 +638,7 @@ trim_left_proc :: proc(s: []byte, p: proc(rune) -> bool) -> []byte {
|
||||
|
||||
index_rune :: proc(s: []byte, r: rune) -> int {
|
||||
switch {
|
||||
case 0 <= r && r < utf8.RUNE_SELF:
|
||||
case u32(r) < utf8.RUNE_SELF:
|
||||
return index_byte(s, byte(r))
|
||||
|
||||
case r == utf8.RUNE_ERROR:
|
||||
|
||||
+20
-39
@@ -16,8 +16,8 @@ reader_init :: proc(r: ^Reader, s: []byte) {
|
||||
}
|
||||
|
||||
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
|
||||
s.stream_data = r
|
||||
s.stream_vtable = _reader_vtable
|
||||
s.data = r
|
||||
s.procedure = _reader_proc
|
||||
return
|
||||
}
|
||||
|
||||
@@ -137,41 +137,22 @@ reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
|
||||
|
||||
@(private)
|
||||
_reader_vtable := &io.Stream_VTable{
|
||||
impl_size = proc(s: io.Stream) -> i64 {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_size(r)
|
||||
},
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read(r, p)
|
||||
},
|
||||
impl_read_at = proc(s: io.Stream, p: []byte, off: i64) -> (n: int, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read_at(r, p, off)
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read_byte(r)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_unread_byte(r)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (ch: rune, size: int, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read_rune(r)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_unread_rune(r)
|
||||
},
|
||||
impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_seek(r, offset, whence)
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_write_to(r, w)
|
||||
},
|
||||
_reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
r := (^Reader)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
return io._i64_err(reader_read(r, p))
|
||||
case .Read_At:
|
||||
return io._i64_err(reader_read_at(r, p, offset))
|
||||
case .Seek:
|
||||
n, err = reader_seek(r, offset, whence)
|
||||
return
|
||||
case .Size:
|
||||
n = reader_size(r)
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Read, .Read_At, .Seek, .Size, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
|
||||
@@ -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[:]
|
||||
}
|
||||
@@ -1118,7 +1118,7 @@ expand_macro :: proc(cpp: ^Preprocessor, rest: ^^Token, tok: ^Token) -> bool {
|
||||
|
||||
search_include_next :: proc(cpp: ^Preprocessor, filename: string) -> (path: string, ok: bool) {
|
||||
for ; cpp.include_next_index < len(cpp.include_paths); cpp.include_next_index += 1 {
|
||||
tpath := filepath.join(elems={cpp.include_paths[cpp.include_next_index], filename}, allocator=context.temp_allocator)
|
||||
tpath := filepath.join({cpp.include_paths[cpp.include_next_index], filename}, allocator=context.temp_allocator)
|
||||
if os.exists(tpath) {
|
||||
return strings.clone(tpath), true
|
||||
}
|
||||
@@ -1136,7 +1136,7 @@ search_include_paths :: proc(cpp: ^Preprocessor, filename: string) -> (path: str
|
||||
}
|
||||
|
||||
for include_path in cpp.include_paths {
|
||||
tpath := filepath.join(elems={include_path, filename}, allocator=context.temp_allocator)
|
||||
tpath := filepath.join({include_path, filename}, allocator=context.temp_allocator)
|
||||
if os.exists(tpath) {
|
||||
path, ok = strings.clone(tpath), true
|
||||
cpp.filepath_cache[filename] = path
|
||||
|
||||
@@ -127,7 +127,7 @@ advance_rune :: proc(t: ^Tokenizer) {
|
||||
}
|
||||
|
||||
advance_rune_n :: proc(t: ^Tokenizer, n: int) {
|
||||
for in 0..<n {
|
||||
for _ in 0..<n {
|
||||
advance_rune(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ foreign libc {
|
||||
// 7.3.8 Power and absolute-value functions
|
||||
cabs :: proc(z: complex_double) -> complex_double ---
|
||||
cabsf :: proc(z: complex_float) -> complex_float ---
|
||||
cpow :: proc(z: complex_double) -> complex_double ---
|
||||
cpowf :: proc(z: complex_float) -> complex_float ---
|
||||
cpow :: proc(x, y: complex_double) -> complex_double ---
|
||||
cpowf :: proc(x, y: complex_float) -> complex_float ---
|
||||
csqrt :: proc(z: complex_double) -> complex_double ---
|
||||
csqrtf :: proc(z: complex_float) -> complex_float ---
|
||||
|
||||
|
||||
+15
-2
@@ -14,11 +14,24 @@ when ODIN_OS == .Windows {
|
||||
// EDOM,
|
||||
// EILSEQ
|
||||
// ERANGE
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||
when ODIN_OS == .Linux {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__libc_errno_location")
|
||||
@(link_name="__errno_location")
|
||||
_get_errno :: proc() -> ^int ---
|
||||
}
|
||||
|
||||
EDOM :: 33
|
||||
EILSEQ :: 84
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
when ODIN_OS == .FreeBSD {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__error")
|
||||
_get_errno :: proc() -> ^int ---
|
||||
}
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ fmin :: proc{libc_fmin, libc_fminf}
|
||||
fma :: proc{libc_fma, libc_fmaf}
|
||||
|
||||
// But retain the 'f' suffix-variant functions as well so they can be used,
|
||||
// a trick is used here where we use explicit procedrual overloading of one
|
||||
// a trick is used here where we use explicit procedural overloading of one
|
||||
// procedure. This is done because the foreign block is marked @(private) and
|
||||
// aliasing functions does not remove privateness from the entity.
|
||||
acosf :: proc{libc_acosf}
|
||||
|
||||
@@ -63,4 +63,4 @@ foreign libc {
|
||||
// strictly conformant C implementation is 16 on the platforms we care about.
|
||||
// The choice of 4096 bytes for storage of this type is more than enough on all
|
||||
// relevant platforms.
|
||||
jmp_buf :: struct #align 16 { _: [4096]char, }
|
||||
jmp_buf :: struct #align(16) { _: [4096]char, }
|
||||
|
||||
@@ -18,7 +18,7 @@ foreign _ {
|
||||
// strictly conformant C implementation is 16 on the platforms we care about.
|
||||
// The choice of 4096 bytes for storage of this type is more than enough on all
|
||||
// relevant platforms.
|
||||
va_list :: struct #align 16 {
|
||||
va_list :: struct #align(16) {
|
||||
_: [4096]u8,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package libc
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
foreign import libc {
|
||||
"system:libucrt.lib",
|
||||
"system:legacy_stdio_definitions.lib",
|
||||
}
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
@@ -179,7 +182,7 @@ foreign libc {
|
||||
fscanf :: proc(stream: ^FILE, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
printf :: proc(format: cstring, #c_vararg args: ..any) -> int ---
|
||||
scanf :: proc(format: cstring, #c_vararg args: ..any) -> int ---
|
||||
snprintf :: proc(s: [^]char, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
snprintf :: proc(s: [^]char, n: size_t, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
sscanf :: proc(s, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
vfprintf :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---
|
||||
vfscanf :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---
|
||||
@@ -196,7 +199,7 @@ 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, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||
|
||||
+27
-1
@@ -88,7 +88,6 @@ foreign libc {
|
||||
srand :: proc(seed: uint) ---
|
||||
|
||||
// 7.22.3 Memory management functions
|
||||
aligned_alloc :: proc(aligment, size: size_t) -> rawptr ---
|
||||
calloc :: proc(nmemb, size: size_t) -> rawptr ---
|
||||
free :: proc(ptr: rawptr) ---
|
||||
malloc :: proc(size: size_t) -> rawptr ---
|
||||
@@ -125,3 +124,30 @@ foreign libc {
|
||||
mbstowcs :: proc(pwcs: ^wchar_t, s: cstring, n: size_t) -> size_t ---
|
||||
wcstombs :: proc(s: [^]char, pwcs: ^wchar_t, n: size_t) -> size_t ---
|
||||
}
|
||||
|
||||
|
||||
aligned_alloc :: #force_inline proc "c" (alignment, size: size_t) -> rawptr {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
_aligned_malloc :: proc(size, alignment: size_t) -> rawptr ---
|
||||
}
|
||||
return _aligned_malloc(size=size, alignment=alignment)
|
||||
} else {
|
||||
foreign libc {
|
||||
aligned_alloc :: proc(alignment, size: size_t) -> rawptr ---
|
||||
}
|
||||
return aligned_alloc(alignment=alignment, size=size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
aligned_free :: #force_inline proc "c" (ptr: rawptr) {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
_aligned_free :: proc(ptr: rawptr) ---
|
||||
}
|
||||
_aligned_free(ptr)
|
||||
} else {
|
||||
free(ptr)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ tss_dtor_t :: proc "c" (rawptr)
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc {
|
||||
"system:libucrt.lib",
|
||||
"system:msvcprt.lib"
|
||||
"system:msvcprt.lib",
|
||||
}
|
||||
|
||||
thrd_success :: 0 // _Thrd_success
|
||||
@@ -44,7 +44,7 @@ when ODIN_OS == .Windows {
|
||||
@(link_name="_Cnd_destroy") cnd_destroy :: proc(cond: ^cnd_t) ---
|
||||
@(link_name="_Cnd_init") cnd_init :: proc(cond: ^cnd_t) -> int ---
|
||||
@(link_name="_Cnd_signal") cnd_signal :: proc(cond: ^cnd_t) -> int ---
|
||||
@(link_name="_Cnd_timedwait") cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
|
||||
@(link_name="_Cnd_timedwait") cnd_timedwait :: proc(cond: ^cnd_t, mtx: ^mtx_t, ts: ^timespec) -> int ---
|
||||
@(link_name="_Cnd_wait") cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
|
||||
|
||||
// 7.26.4 Mutex functions
|
||||
@@ -77,7 +77,7 @@ when ODIN_OS == .Windows {
|
||||
when ODIN_OS == .Linux {
|
||||
foreign import libc {
|
||||
"system:c",
|
||||
"system:pthread"
|
||||
"system:pthread",
|
||||
}
|
||||
|
||||
thrd_success :: 0
|
||||
@@ -108,7 +108,7 @@ when ODIN_OS == .Linux {
|
||||
cnd_destroy :: proc(cond: ^cnd_t) ---
|
||||
cnd_init :: proc(cond: ^cnd_t) -> int ---
|
||||
cnd_signal :: proc(cond: ^cnd_t) -> int ---
|
||||
cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
|
||||
cnd_timedwait :: proc(cond: ^cnd_t, mtx: ^mtx_t, ts: ^timespec) -> int ---
|
||||
cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
|
||||
|
||||
// 7.26.4 Mutex functions
|
||||
|
||||
@@ -35,12 +35,12 @@ when ODIN_OS == .Windows {
|
||||
clock_t :: distinct long
|
||||
time_t :: distinct i64
|
||||
|
||||
timespec :: struct #align 8 {
|
||||
timespec :: struct #align(8) {
|
||||
tv_sec: time_t,
|
||||
tv_nsec: long,
|
||||
}
|
||||
|
||||
tm :: struct #align 8 {
|
||||
tm :: struct #align(8) {
|
||||
tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package libc
|
||||
|
||||
import "core:c"
|
||||
|
||||
#assert(!ODIN_NO_CRT, `"core:c/libc" cannot be imported when '-no-crt' is used`)
|
||||
|
||||
char :: c.char // assuming -funsigned-char
|
||||
|
||||
schar :: c.schar
|
||||
|
||||
@@ -98,7 +98,7 @@ foreign libc {
|
||||
}
|
||||
|
||||
// Large enough and aligned enough for any wide-spread in-use libc.
|
||||
mbstate_t :: struct #align 16 { _: [32]char, }
|
||||
mbstate_t :: struct #align(16) { _: [32]char, }
|
||||
|
||||
// Odin does not have default argument promotion so the need for a separate type
|
||||
// here isn't necessary, though make it distinct just to be safe.
|
||||
|
||||
+68
-32
@@ -188,7 +188,8 @@ input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Erro
|
||||
}
|
||||
|
||||
input_size_from_stream :: proc(z: ^Context_Stream_Input) -> (res: i64, err: Error) {
|
||||
return io.size(z.input), nil
|
||||
res, _ = io.size(z.input)
|
||||
return
|
||||
}
|
||||
|
||||
input_size :: proc{input_size_from_memory, input_size_from_stream}
|
||||
@@ -212,25 +213,19 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
|
||||
// TODO: REMOVE ALL USE OF context.temp_allocator here
|
||||
// the is literally no need for it
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
_, e := z.input->impl_read(b[:])
|
||||
if e == .None {
|
||||
return b, .None
|
||||
}
|
||||
|
||||
return []u8{}, e
|
||||
_ = io.read(z.input, b[:]) or_return
|
||||
return b, nil
|
||||
}
|
||||
|
||||
read_slice :: proc{read_slice_from_memory, read_slice_from_stream}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) {
|
||||
b, e := read_slice(z, size_of(T))
|
||||
if e == .None {
|
||||
return (^T)(&b[0])^, .None
|
||||
}
|
||||
|
||||
return T{}, e
|
||||
b := read_slice(z, size_of(T)) or_return
|
||||
return (^T)(&b[0])^, nil
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
@@ -247,12 +242,8 @@ read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8,
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) {
|
||||
b, e := read_slice_from_stream(z, 1)
|
||||
if e == .None {
|
||||
return b[0], .None
|
||||
}
|
||||
|
||||
return 0, e
|
||||
b := read_slice_from_stream(z, 1) or_return
|
||||
return b[0], nil
|
||||
}
|
||||
|
||||
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
|
||||
@@ -294,17 +285,32 @@ peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid
|
||||
}
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
peek_data_at_offset_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
|
||||
size :: size_of(T)
|
||||
|
||||
#no_bounds_check {
|
||||
if len(z.input_data) >= size + offset {
|
||||
buf := z.input_data[offset:][:size]
|
||||
return (^T)(&buf[0])^, .None
|
||||
}
|
||||
}
|
||||
|
||||
if len(z.input_data) == 0 {
|
||||
return T{}, .EOF
|
||||
} else {
|
||||
return T{}, .Short_Buffer
|
||||
}
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
|
||||
size :: size_of(T)
|
||||
|
||||
// Get current position to read from.
|
||||
curr, e1 := z.input->impl_seek(0, .Current)
|
||||
if e1 != .None {
|
||||
return T{}, e1
|
||||
}
|
||||
r, e2 := io.to_reader_at(z.input)
|
||||
if !e2 {
|
||||
curr := z.input->impl_seek(0, .Current) or_return
|
||||
r, e1 := io.to_reader_at(z.input)
|
||||
if !e1 {
|
||||
return T{}, .Empty
|
||||
}
|
||||
when size <= 128 {
|
||||
@@ -312,8 +318,8 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
||||
} else {
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
}
|
||||
_, e3 := io.read_at(r, b[:], curr)
|
||||
if e3 != .None {
|
||||
_, e2 := io.read_at(r, b[:], curr)
|
||||
if e2 != .None {
|
||||
return T{}, .Empty
|
||||
}
|
||||
|
||||
@@ -321,7 +327,37 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
||||
return res, .None
|
||||
}
|
||||
|
||||
peek_data :: proc{peek_data_from_memory, peek_data_from_stream}
|
||||
@(optimization_mode="speed")
|
||||
peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
|
||||
size :: size_of(T)
|
||||
|
||||
// Get current position to return to.
|
||||
cur_pos := z.input->impl_seek(0, .Current) or_return
|
||||
// Seek to offset.
|
||||
pos := z.input->impl_seek(offset, .Start) or_return
|
||||
|
||||
r, e3 := io.to_reader_at(z.input)
|
||||
if !e3 {
|
||||
return T{}, .Empty
|
||||
}
|
||||
when size <= 128 {
|
||||
b: [size]u8
|
||||
} else {
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
}
|
||||
_, e4 := io.read_at(r, b[:], pos)
|
||||
if e4 != .None {
|
||||
return T{}, .Empty
|
||||
}
|
||||
|
||||
// Return read head to original position.
|
||||
z.input->impl_seek(cur_pos, .Start)
|
||||
|
||||
res = (^T)(&b[0])^
|
||||
return res, .None
|
||||
}
|
||||
|
||||
peek_data :: proc{peek_data_from_memory, peek_data_from_stream, peek_data_at_offset_from_memory, peek_data_at_offset_from_stream}
|
||||
|
||||
|
||||
|
||||
@@ -407,7 +443,7 @@ peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width:
|
||||
if z.num_bits < u64(width) {
|
||||
refill_lsb(z)
|
||||
}
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
@@ -415,7 +451,7 @@ peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width:
|
||||
if z.num_bits < u64(width) {
|
||||
refill_lsb(z)
|
||||
}
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
|
||||
@@ -423,13 +459,13 @@ peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
|
||||
@(optimization_mode="speed")
|
||||
peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
|
||||
assert(z.num_bits >= u64(width))
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
|
||||
assert(z.num_bits >= u64(width))
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+ignore
|
||||
//+build ignore
|
||||
package gzip
|
||||
|
||||
/*
|
||||
|
||||
@@ -335,10 +335,8 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
|
||||
|
||||
// fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size);
|
||||
|
||||
zlib_error := zlib.inflate_raw(z=z, expected_output_size=expected_output_size)
|
||||
if zlib_error != nil {
|
||||
return zlib_error
|
||||
}
|
||||
zlib.inflate_raw(z, expected_output_size=expected_output_size) or_return
|
||||
|
||||
/*
|
||||
Read CRC32 using the ctx bit reader because zlib may leave bytes in there.
|
||||
*/
|
||||
|
||||
@@ -177,12 +177,10 @@ decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocato
|
||||
max_output_size := decompress_bound(len(input), model)
|
||||
|
||||
buf: [dynamic]u8
|
||||
if !resize(&buf, max_output_size) {
|
||||
return "", .Out_Of_Memory
|
||||
}
|
||||
resize(&buf, max_output_size) or_return
|
||||
|
||||
length, result := decompress_slice_to_output_buffer(input, buf[:])
|
||||
resize(&buf, length)
|
||||
resize(&buf, length) or_return
|
||||
return string(buf[:]), result
|
||||
}
|
||||
decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
|
||||
@@ -307,12 +305,10 @@ compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := cont
|
||||
max_output_size := compress_bound(len(input))
|
||||
|
||||
buf: [dynamic]u8
|
||||
if !resize(&buf, max_output_size) {
|
||||
return {}, .Out_Of_Memory
|
||||
}
|
||||
resize(&buf, max_output_size) or_return
|
||||
|
||||
length, result := compress_string_to_buffer(input, buf[:])
|
||||
resize(&buf, length)
|
||||
resize(&buf, length) or_return
|
||||
return buf[:length], result
|
||||
}
|
||||
compress :: proc{compress_string_to_buffer, compress_string}
|
||||
@@ -1,4 +1,4 @@
|
||||
//+ignore
|
||||
//+build ignore
|
||||
package zlib
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//+vet !using-param
|
||||
package zlib
|
||||
|
||||
/*
|
||||
@@ -146,15 +147,7 @@ grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
|
||||
Double until we reach the maximum allowed.
|
||||
*/
|
||||
new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX)
|
||||
resize(buf, new_size)
|
||||
if len(buf) != new_size {
|
||||
/*
|
||||
Resize failed.
|
||||
*/
|
||||
return .Resize_Failed
|
||||
}
|
||||
|
||||
return nil
|
||||
return resize(buf, new_size)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -181,7 +174,7 @@ write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_ch
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
|
||||
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
|
||||
/*
|
||||
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
|
||||
without having to worry about wrapping, so no need for a temp allocation to give to
|
||||
@@ -305,10 +298,10 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
||||
code := u16(compress.peek_bits_lsb(z,16))
|
||||
|
||||
k := int(z_bit_reverse(code, 16))
|
||||
s: u8
|
||||
|
||||
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; {
|
||||
if k < t.maxcode[s] {
|
||||
s: u8 = HUFFMAN_FAST_BITS+1
|
||||
for {
|
||||
#no_bounds_check if k < t.maxcode[s] {
|
||||
break
|
||||
}
|
||||
s += 1
|
||||
@@ -471,7 +464,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
||||
}
|
||||
|
||||
// Parse ZLIB stream without header.
|
||||
inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return
|
||||
inflate_raw(ctx, expected_output_size=expected_output_size) or_return
|
||||
|
||||
if !raw {
|
||||
compress.discard_to_next_byte_lsb(ctx)
|
||||
@@ -509,8 +502,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
/*
|
||||
Try to pre-allocate the output buffer.
|
||||
*/
|
||||
reserve(&z.output.buf, expected_output_size)
|
||||
resize (&z.output.buf, expected_output_size)
|
||||
reserve(&z.output.buf, expected_output_size) or_return
|
||||
resize (&z.output.buf, expected_output_size) or_return
|
||||
}
|
||||
|
||||
if len(z.output.buf) != expected_output_size {
|
||||
@@ -653,7 +646,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
}
|
||||
|
||||
if int(z.bytes_written) != len(z.output.buf) {
|
||||
resize(&z.output.buf, int(z.bytes_written))
|
||||
resize(&z.output.buf, int(z.bytes_written)) or_return
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -665,7 +658,7 @@ inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, e
|
||||
ctx.input_data = input
|
||||
ctx.output = buf
|
||||
|
||||
return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size)
|
||||
return inflate_from_context(&ctx, raw=raw, expected_output_size=expected_output_size)
|
||||
}
|
||||
|
||||
inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
|
||||
@@ -674,7 +667,7 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
|
||||
ctx.input_data = input
|
||||
ctx.output = buf
|
||||
|
||||
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
|
||||
return inflate_raw(&ctx, expected_output_size=expected_output_size)
|
||||
}
|
||||
|
||||
inflate :: proc{inflate_from_context, inflate_from_byte_array}
|
||||
|
||||
@@ -27,27 +27,28 @@ Bit_Array_Iterator :: struct {
|
||||
word_idx: int,
|
||||
bit_idx: uint,
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - the array to iterate over
|
||||
Wraps a `Bit_Array` into an Iterator
|
||||
|
||||
Out:
|
||||
- it: ^Bit_Array_Iterator - the iterator that holds iteration state
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
|
||||
Returns:
|
||||
- it: Iterator struct
|
||||
*/
|
||||
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.
|
||||
Returns the next bit, including its set-state. ok=false once exhausted
|
||||
|
||||
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
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
|
||||
Returns:
|
||||
- set: `true` if the bit at `index` is set.
|
||||
- index: The next bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
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
|
||||
@@ -64,39 +65,51 @@ iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok:
|
||||
|
||||
return set, index, true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||
Returns the next Set Bit, for example if `0b1010`, then the iterator will return index={1, 3} over two calls.
|
||||
|
||||
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
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
|
||||
Returns:
|
||||
- index: The next *set* bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
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.
|
||||
Returns the next Unset Bit, for example if `0b1010`, then the iterator will return index={0, 2} over two calls.
|
||||
|
||||
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
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
|
||||
Returns:
|
||||
- index: The next *unset* bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||
return iterate_internal_(it, false)
|
||||
}
|
||||
/*
|
||||
Iterates through set/unset bits
|
||||
|
||||
*Private*
|
||||
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
- ITERATE_SET_BITS: `true` for returning only set bits, false for returning only unset bits
|
||||
|
||||
Returns:
|
||||
- index: The next *unset* bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
@(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,
|
||||
// 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 {
|
||||
@@ -106,14 +119,14 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
|
||||
@@ -124,24 +137,21 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
|
||||
}
|
||||
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.
|
||||
Gets the state of a bit in the bit-array
|
||||
|
||||
Out:
|
||||
- res: The bit you're interested in.
|
||||
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
|
||||
The `ok` return value may be ignored.
|
||||
Returns:
|
||||
- res: `true` if the bit at `index` is set.
|
||||
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
|
||||
*/
|
||||
get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) {
|
||||
get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #optional_ok {
|
||||
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
|
||||
@@ -157,18 +167,36 @@ get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
|
||||
|
||||
return res, true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||
- index: The bit index. Can be an enum member.
|
||||
Gets the state of a bit in the bit-array
|
||||
|
||||
Out:
|
||||
- ok: Whether or not we managed to set requested bit.
|
||||
*Bypasses all Checks*
|
||||
|
||||
`set` automatically resizes the Bit Array to accommodate the requested index if needed.
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
|
||||
Returns:
|
||||
- `true` if bit is set
|
||||
*/
|
||||
set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
|
||||
unsafe_get :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint) -> bool #no_bounds_check {
|
||||
return bool((ba.bits[index >> INDEX_SHIFT] >> uint(index & INDEX_MASK)) & 1)
|
||||
}
|
||||
/*
|
||||
Sets the state of a bit in the bit-array
|
||||
|
||||
*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
|
||||
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
- set_to: `true` sets the bit on, `false` to turn it off
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
- ok: Whether the set was successful, `false` on allocation failure or bad index
|
||||
*/
|
||||
set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator := context.allocator) -> (ok: bool) {
|
||||
|
||||
idx := int(index) - ba.bias
|
||||
|
||||
@@ -181,38 +209,97 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
|
||||
resize_if_needed(ba, leg_index) or_return
|
||||
|
||||
ba.max_index = max(idx, ba.max_index)
|
||||
ba.bits[leg_index] |= 1 << uint(bit_index)
|
||||
|
||||
if set_to{ ba.bits[leg_index] |= 1 << uint(bit_index) }
|
||||
else { 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).
|
||||
Sets the state of a bit in the bit-array
|
||||
|
||||
*Bypasses all checks*
|
||||
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
*/
|
||||
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
|
||||
unsafe_set :: proc(ba: ^Bit_Array, bit: int) #no_bounds_check {
|
||||
ba.bits[bit >> INDEX_SHIFT] |= 1 << uint(bit & INDEX_MASK)
|
||||
}
|
||||
/*
|
||||
Unsets the state of a bit in the bit-array. (Convienence wrapper for `set`)
|
||||
|
||||
*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
|
||||
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
- ok: Whether the unset was successful, `false` on allocation failure or bad index
|
||||
*/
|
||||
unset :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
|
||||
return set(ba, index, false, allocator)
|
||||
}
|
||||
/*
|
||||
Unsets the state of a bit in the bit-array
|
||||
|
||||
*Bypasses all Checks*
|
||||
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
*/
|
||||
unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
|
||||
b.bits[bit >> INDEX_SHIFT] &= ~(1 << uint(bit & INDEX_MASK))
|
||||
}
|
||||
/*
|
||||
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
||||
|
||||
*Allocates (`new(Bit_Array) & make(ba.bits)`)*
|
||||
|
||||
Inputs:
|
||||
- max_index: maximum starting index
|
||||
- min_index: minimum starting index (used as a bias)
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
- ba: Allocates a bit_Array, backing data is set to `max-min / 64` indices, rounded up (eg 65 - 0 allocates for [2]u64).
|
||||
*/
|
||||
create :: proc(max_index: int, min_index: int = 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
|
||||
|
||||
if size_in_bits & INDEX_MASK > 0 {legs+=1}
|
||||
bits, err := make([dynamic]u64, legs)
|
||||
ok = err == mem.Allocator_Error.None
|
||||
res = new(Bit_Array)
|
||||
res.bits = bits
|
||||
res.bias = min_index
|
||||
res.max_index = max_index
|
||||
res.free_pointer = true
|
||||
return res, resize_if_needed(res, legs)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Sets all bits to `false`.
|
||||
Sets all values in the Bit_Array to zero.
|
||||
|
||||
Inputs:
|
||||
- ba: The target Bit_Array
|
||||
*/
|
||||
clear :: proc(ba: ^Bit_Array) {
|
||||
if ba == nil { return }
|
||||
mem.zero_slice(ba.bits[:])
|
||||
}
|
||||
|
||||
/*
|
||||
Releases the memory used by the Bit Array.
|
||||
Deallocates the Bit_Array and its backing storage
|
||||
|
||||
Inputs:
|
||||
- ba: The target Bit_Array
|
||||
*/
|
||||
destroy :: proc(ba: ^Bit_Array) {
|
||||
if ba == nil { return }
|
||||
@@ -221,9 +308,8 @@ destroy :: proc(ba: ^Bit_Array) {
|
||||
free(ba)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Resizes the Bit Array. For internal use.
|
||||
Resizes the Bit Array. For internal use. Provisions needed capacity+1
|
||||
If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
|
||||
*/
|
||||
@(private="file")
|
||||
|
||||
@@ -20,10 +20,10 @@ List :: struct {
|
||||
|
||||
|
||||
Node :: struct {
|
||||
next, prev: ^Node,
|
||||
prev, next: ^Node,
|
||||
}
|
||||
|
||||
push_front :: proc(list: ^List, node: ^Node) {
|
||||
push_front :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if list.head != nil {
|
||||
list.head.prev = node
|
||||
node.prev, node.next = nil, list.head
|
||||
@@ -34,7 +34,7 @@ push_front :: proc(list: ^List, node: ^Node) {
|
||||
}
|
||||
}
|
||||
|
||||
push_back :: proc(list: ^List, node: ^Node) {
|
||||
push_back :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if list.tail != nil {
|
||||
list.tail.next = node
|
||||
node.prev, node.next = list.tail, nil
|
||||
@@ -45,7 +45,7 @@ push_back :: proc(list: ^List, node: ^Node) {
|
||||
}
|
||||
}
|
||||
|
||||
remove :: proc(list: ^List, node: ^Node) {
|
||||
remove :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if node != nil {
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
@@ -83,12 +83,34 @@ remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
|
||||
}
|
||||
}
|
||||
|
||||
remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^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 {
|
||||
|
||||
|
||||
is_empty :: proc "contextless" (list: ^List) -> bool {
|
||||
return list.head == nil
|
||||
}
|
||||
|
||||
pop_front :: proc(list: ^List) -> ^Node {
|
||||
pop_front :: proc "contextless" (list: ^List) -> ^Node {
|
||||
link := list.head
|
||||
if link == nil {
|
||||
return nil
|
||||
@@ -108,7 +130,7 @@ pop_front :: proc(list: ^List) -> ^Node {
|
||||
return link
|
||||
|
||||
}
|
||||
pop_back :: proc(list: ^List) -> ^Node {
|
||||
pop_back :: proc "contextless" (list: ^List) -> ^Node {
|
||||
link := list.tail
|
||||
if link == nil {
|
||||
return nil
|
||||
@@ -134,25 +156,25 @@ Iterator :: struct($T: typeid) {
|
||||
offset: uintptr,
|
||||
}
|
||||
|
||||
iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
iterator_head :: proc "contextless" (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)
|
||||
iterator_tail :: proc "contextless" (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)
|
||||
iterator_from_node :: proc "contextless" (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) {
|
||||
iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
@@ -162,7 +184,7 @@ iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
return (^T)(uintptr(node) - it.offset), true
|
||||
}
|
||||
|
||||
iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
|
||||
@@ -85,7 +85,6 @@ _shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool {
|
||||
_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]) {
|
||||
|
||||
@@ -14,7 +14,7 @@ Queue :: struct($T: typeid) {
|
||||
DEFAULT_CAPACITY :: 16
|
||||
|
||||
// Procedure to initialize a queue
|
||||
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool {
|
||||
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> runtime.Allocator_Error {
|
||||
if q.data.allocator.procedure == nil {
|
||||
q.data.allocator = allocator
|
||||
}
|
||||
@@ -22,7 +22,9 @@ init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := contex
|
||||
return reserve(q, capacity)
|
||||
}
|
||||
|
||||
// Procedure to initialize a queue from a fixed backing slice
|
||||
// Procedure to initialize a queue from a fixed backing slice.
|
||||
// The contents of the `backing` will be overwritten as items are pushed onto the `Queue`.
|
||||
// Any previous contents are not available.
|
||||
init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
|
||||
clear(q)
|
||||
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
|
||||
@@ -34,6 +36,21 @@ init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Procedure to initialize a queue from a fixed backing slice.
|
||||
// Existing contents are preserved and available on the queue.
|
||||
init_with_contents :: 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},
|
||||
}
|
||||
q.len = len(backing)
|
||||
q.offset = len(backing)
|
||||
return true
|
||||
}
|
||||
|
||||
// Procedure to destroy a queue
|
||||
destroy :: proc(q: ^$Q/Queue($T)) {
|
||||
delete(q.data)
|
||||
@@ -55,11 +72,11 @@ space :: proc(q: $Q/Queue($T)) -> int {
|
||||
}
|
||||
|
||||
// Reserve enough space for at least the specified capacity
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool {
|
||||
if uint(capacity) > q.len {
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error {
|
||||
if capacity > space(q^) {
|
||||
return _grow(q, uint(capacity))
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +86,23 @@ get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T {
|
||||
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]
|
||||
}
|
||||
front_ptr :: 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]
|
||||
}
|
||||
back_ptr :: 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))
|
||||
|
||||
@@ -82,26 +116,38 @@ get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^
|
||||
return &q.data[idx]
|
||||
}
|
||||
|
||||
peek_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
|
||||
runtime.bounds_check_error_loc(loc, 0, builtin.len(q.data))
|
||||
idx := q.offset%builtin.len(q.data)
|
||||
return &q.data[idx]
|
||||
}
|
||||
|
||||
peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
|
||||
runtime.bounds_check_error_loc(loc, int(q.len - 1), builtin.len(q.data))
|
||||
idx := (uint(q.len - 1)+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 {
|
||||
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
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
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Push an element to the front of the queue
|
||||
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
||||
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
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
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +190,7 @@ pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
||||
}
|
||||
|
||||
// Push multiple elements to the front of the queue
|
||||
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
|
||||
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
n := uint(builtin.len(elems))
|
||||
if space(q^) < int(n) {
|
||||
_grow(q, q.len + n) or_return
|
||||
@@ -159,7 +205,7 @@ push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
|
||||
copy(q.data[insert_from:], elems[:insert_to])
|
||||
copy(q.data[:insert_from], elems[insert_to:])
|
||||
q.len += n
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Consume `n` elements from the front of the queue
|
||||
@@ -196,7 +242,7 @@ clear :: proc(q: ^$Q/Queue($T)) {
|
||||
|
||||
|
||||
// Internal growinh procedure
|
||||
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
|
||||
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error {
|
||||
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
|
||||
@@ -205,5 +251,5 @@ _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
|
||||
copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
|
||||
q.offset += new_capacity - n
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package container_small_array
|
||||
|
||||
import "core:builtin"
|
||||
import "core:runtime"
|
||||
_ :: runtime
|
||||
|
||||
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||
data: [N]T,
|
||||
@@ -8,40 +10,54 @@ Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||
}
|
||||
|
||||
|
||||
len :: proc(a: $A/Small_Array) -> int {
|
||||
len :: proc "contextless" (a: $A/Small_Array) -> int {
|
||||
return a.len
|
||||
}
|
||||
|
||||
cap :: proc(a: $A/Small_Array) -> int {
|
||||
cap :: proc "contextless" (a: $A/Small_Array) -> int {
|
||||
return builtin.len(a.data)
|
||||
}
|
||||
|
||||
space :: proc(a: $A/Small_Array) -> int {
|
||||
space :: proc "contextless" (a: $A/Small_Array) -> int {
|
||||
return builtin.len(a.data) - a.len
|
||||
}
|
||||
|
||||
slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
|
||||
slice :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> []T {
|
||||
return a.data[:a.len]
|
||||
}
|
||||
|
||||
|
||||
get :: proc(a: $A/Small_Array($N, $T), index: int) -> T {
|
||||
get :: proc "contextless" (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 {
|
||||
get_ptr :: proc "contextless" (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) {
|
||||
get_safe :: proc(a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
|
||||
if index < 0 || index >= a.len {
|
||||
return {}, false
|
||||
}
|
||||
return a.data[index], true
|
||||
}
|
||||
|
||||
get_ptr_safe :: proc(a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
|
||||
if index < 0 || index >= a.len {
|
||||
return {}, false
|
||||
}
|
||||
return &a.data[index], true
|
||||
}
|
||||
|
||||
set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||
a.data[index] = item
|
||||
}
|
||||
|
||||
resize :: proc(a: ^$A/Small_Array, length: int) {
|
||||
resize :: proc "contextless" (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 {
|
||||
push_back :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
if a.len < cap(a^) {
|
||||
a.data[a.len] = item
|
||||
a.len += 1
|
||||
@@ -50,7 +66,7 @@ push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
push_front :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
if a.len < cap(a^) {
|
||||
a.len += 1
|
||||
data := slice(a)
|
||||
@@ -61,14 +77,14 @@ push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||
pop_back :: proc "odin" (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 {
|
||||
pop_front :: proc "odin" (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)
|
||||
@@ -77,7 +93,7 @@ pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||
return item
|
||||
}
|
||||
|
||||
pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||
pop_back_safe :: proc "contextless" (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
|
||||
@@ -86,31 +102,60 @@ pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||
pop_front_safe :: proc "contextless" (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) {
|
||||
consume :: proc "odin" (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)) {
|
||||
ordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
|
||||
runtime.bounds_check_error_loc(loc, index, a.len)
|
||||
if index+1 < a.len {
|
||||
copy(a.data[index:], a.data[index+1:])
|
||||
}
|
||||
a.len -= 1
|
||||
}
|
||||
|
||||
unordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
|
||||
runtime.bounds_check_error_loc(loc, index, a.len)
|
||||
n := a.len-1
|
||||
if index != n {
|
||||
a.data[index] = a.data[n]
|
||||
}
|
||||
a.len -= 1
|
||||
}
|
||||
|
||||
clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) {
|
||||
resize(a, 0)
|
||||
}
|
||||
|
||||
push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) {
|
||||
push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) {
|
||||
n := copy(a.data[a.len:], items[:])
|
||||
a.len += n
|
||||
}
|
||||
|
||||
inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int) -> bool #no_bounds_check {
|
||||
if a.len < cap(a^) && index >= 0 && index <= len(a^) {
|
||||
a.len += 1
|
||||
for i := a.len - 1; i >= index + 1; i -= 1 {
|
||||
a.data[i] = a.data[i - 1]
|
||||
}
|
||||
a.data[index] = item
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
append_elem :: push_back
|
||||
append_elems :: push_back_elems
|
||||
push :: proc{push_back, push_back_elems}
|
||||
|
||||
@@ -32,7 +32,7 @@ init :: proc(sorter: ^$S/Sorter($K)) {
|
||||
}
|
||||
|
||||
destroy :: proc(sorter: ^$S/Sorter($K)) {
|
||||
for _, v in &sorter.relations {
|
||||
for _, v in sorter.relations {
|
||||
delete(v.dependents)
|
||||
}
|
||||
delete(sorter.relations)
|
||||
@@ -80,11 +80,13 @@ sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]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 root in sorted {
|
||||
for k, _ in relations[root].dependents {
|
||||
relation := &relations[k]
|
||||
relation.dependencies -= 1
|
||||
if relation.dependencies == 0 {
|
||||
append(&sorted, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+42
-51
@@ -1,95 +1,86 @@
|
||||
# crypto
|
||||
A crypto library for the Odin language
|
||||
|
||||
A cryptography library for the Odin language
|
||||
|
||||
## Supported
|
||||
|
||||
This library offers various algorithms implemented in Odin.
|
||||
Please see the chart below for the options.
|
||||
Please see the chart below for some of 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) | ✔️ |
|
||||
| legacy/[Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| legacy/[MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ |
|
||||
| legacy/[SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ |
|
||||
|
||||
#### 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(...)`.
|
||||
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, `SHA-2` offers different sizes.
|
||||
Computing a 512-bit hash is therefore achieved by calling `sha2.hash_512(...)`.
|
||||
|
||||
#### 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"
|
||||
import "core:crypto/blake2b"
|
||||
|
||||
main :: proc() {
|
||||
input := "foo"
|
||||
|
||||
// Compute the hash, using the high level API
|
||||
computed_hash := md4.hash(input)
|
||||
computed_hash := blake2b.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[:])
|
||||
hash := make([]byte, sha2.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash
|
||||
blake2b.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[:])
|
||||
ctx: blake2b.Context
|
||||
computed_hash_low: [blake2b.DIGEST_SIZE]byte
|
||||
blake2b.init(&ctx)
|
||||
blake2b.update(&ctx, transmute([]byte)input)
|
||||
blake2b.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.
|
||||
## Implementation considerations
|
||||
|
||||
### 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.
|
||||
- The crypto packages are not thread-safe.
|
||||
- Best-effort is make to mitigate timing side-channels on reasonable
|
||||
architectures. Architectures that are known to be unreasonable include
|
||||
but are not limited to i386, i486, and WebAssembly.
|
||||
- Some but not all of the packages attempt to santize sensitive data,
|
||||
however this is not done consistently through the library at the moment.
|
||||
As Thomas Pornin puts it "In general, such memory cleansing is a fool's
|
||||
quest."
|
||||
- All of these packages have not received independent third party review.
|
||||
|
||||
### ToDo
|
||||
* Ciphers (Symmetric, Asymmetric)
|
||||
* MACs (Message Authentication Code)
|
||||
* CSPRNGs (Cryptographically Secure PseudoRandom Number Generator)
|
||||
* KDFs (Key Derivation Function)
|
||||
* KEAs (Key Exchange Algorithm)
|
||||
## License
|
||||
|
||||
### License
|
||||
This library is made available under the BSD-3 license.
|
||||
@@ -10,12 +10,12 @@ package _blake2
|
||||
Implementation of the BLAKE2 hashing algorithm, as defined in <https://datatracker.ietf.org/doc/html/rfc7693> and <https://www.blake2.net/>
|
||||
*/
|
||||
|
||||
import "../util"
|
||||
import "core:encoding/endian"
|
||||
|
||||
BLAKE2S_BLOCK_SIZE :: 64
|
||||
BLAKE2S_SIZE :: 32
|
||||
BLAKE2B_BLOCK_SIZE :: 128
|
||||
BLAKE2B_SIZE :: 64
|
||||
BLAKE2S_BLOCK_SIZE :: 64
|
||||
BLAKE2S_SIZE :: 32
|
||||
BLAKE2B_BLOCK_SIZE :: 128
|
||||
BLAKE2B_SIZE :: 64
|
||||
|
||||
Blake2s_Context :: struct {
|
||||
h: [8]u32,
|
||||
@@ -28,7 +28,9 @@ Blake2s_Context :: struct {
|
||||
is_keyed: bool,
|
||||
size: byte,
|
||||
is_last_node: bool,
|
||||
cfg: Blake2_Config,
|
||||
cfg: Blake2_Config,
|
||||
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
Blake2b_Context :: struct {
|
||||
@@ -42,15 +44,19 @@ Blake2b_Context :: struct {
|
||||
is_keyed: bool,
|
||||
size: byte,
|
||||
is_last_node: bool,
|
||||
cfg: Blake2_Config,
|
||||
cfg: Blake2_Config,
|
||||
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
Blake2_Config :: struct {
|
||||
size: byte,
|
||||
key: []byte,
|
||||
salt: []byte,
|
||||
size: byte,
|
||||
key: []byte,
|
||||
salt: []byte,
|
||||
person: []byte,
|
||||
tree: union{Blake2_Tree},
|
||||
tree: union {
|
||||
Blake2_Tree,
|
||||
},
|
||||
}
|
||||
|
||||
Blake2_Tree :: struct {
|
||||
@@ -63,11 +69,13 @@ Blake2_Tree :: struct {
|
||||
is_last_node: bool,
|
||||
}
|
||||
|
||||
@(private)
|
||||
BLAKE2S_IV := [8]u32 {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||
}
|
||||
|
||||
@(private)
|
||||
BLAKE2B_IV := [8]u64 {
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
@@ -78,8 +86,14 @@ BLAKE2B_IV := [8]u64 {
|
||||
init :: proc(ctx: ^$T) {
|
||||
when T == Blake2s_Context {
|
||||
block_size :: BLAKE2S_BLOCK_SIZE
|
||||
max_size :: BLAKE2S_SIZE
|
||||
} else when T == Blake2b_Context {
|
||||
block_size :: BLAKE2B_BLOCK_SIZE
|
||||
max_size :: BLAKE2B_SIZE
|
||||
}
|
||||
|
||||
if ctx.cfg.size > max_size {
|
||||
panic("blake2: requested output size exceeeds algorithm max")
|
||||
}
|
||||
|
||||
p := make([]byte, block_size)
|
||||
@@ -106,10 +120,10 @@ init :: proc(ctx: ^$T) {
|
||||
if ctx.cfg.tree != nil {
|
||||
p[2] = ctx.cfg.tree.(Blake2_Tree).fanout
|
||||
p[3] = ctx.cfg.tree.(Blake2_Tree).max_depth
|
||||
util.PUT_U32_LE(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size)
|
||||
endian.unchecked_put_u32le(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size)
|
||||
when T == Blake2s_Context {
|
||||
p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8)
|
||||
p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8)
|
||||
p[10] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 16)
|
||||
p[11] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 24)
|
||||
p[12] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 32)
|
||||
@@ -117,7 +131,7 @@ init :: proc(ctx: ^$T) {
|
||||
p[14] = ctx.cfg.tree.(Blake2_Tree).node_depth
|
||||
p[15] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size
|
||||
} else when T == Blake2b_Context {
|
||||
util.PUT_U64_LE(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
endian.unchecked_put_u64le(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
p[16] = ctx.cfg.tree.(Blake2_Tree).node_depth
|
||||
p[17] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size
|
||||
}
|
||||
@@ -127,10 +141,10 @@ init :: proc(ctx: ^$T) {
|
||||
ctx.size = ctx.cfg.size
|
||||
for i := 0; i < 8; i += 1 {
|
||||
when T == Blake2s_Context {
|
||||
ctx.h[i] = BLAKE2S_IV[i] ~ util.U32_LE(p[i * 4:])
|
||||
ctx.h[i] = BLAKE2S_IV[i] ~ endian.unchecked_get_u32le(p[i * 4:])
|
||||
}
|
||||
when T == Blake2b_Context {
|
||||
ctx.h[i] = BLAKE2B_IV[i] ~ util.U64_LE(p[i * 8:])
|
||||
ctx.h[i] = BLAKE2B_IV[i] ~ endian.unchecked_get_u64le(p[i * 8:])
|
||||
}
|
||||
}
|
||||
if ctx.cfg.tree != nil && ctx.cfg.tree.(Blake2_Tree).is_last_node {
|
||||
@@ -142,13 +156,19 @@ init :: proc(ctx: ^$T) {
|
||||
ctx.is_keyed = true
|
||||
}
|
||||
copy(ctx.ih[:], ctx.h[:])
|
||||
copy(ctx.h[:], ctx.ih[:])
|
||||
copy(ctx.h[:], ctx.ih[:])
|
||||
if ctx.is_keyed {
|
||||
update(ctx, ctx.padded_key[:])
|
||||
}
|
||||
|
||||
ctx.nx = 0
|
||||
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^$T, p: []byte) {
|
||||
update :: proc(ctx: ^$T, p: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
p := p
|
||||
when T == Blake2s_Context {
|
||||
block_size :: BLAKE2S_BLOCK_SIZE
|
||||
@@ -174,15 +194,25 @@ update :: proc "contextless" (ctx: ^$T, p: []byte) {
|
||||
ctx.nx += copy(ctx.x[ctx.nx:], p)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^$T, hash: []byte) {
|
||||
final :: proc(ctx: ^$T, hash: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
when T == Blake2s_Context {
|
||||
if len(hash) < int(ctx.cfg.size) {
|
||||
panic("crypto/blake2s: invalid destination digest size")
|
||||
}
|
||||
blake2s_final(ctx, hash)
|
||||
}
|
||||
when T == Blake2b_Context {
|
||||
} else when T == Blake2b_Context {
|
||||
if len(hash) < int(ctx.cfg.size) {
|
||||
panic("crypto/blake2b: invalid destination digest size")
|
||||
}
|
||||
blake2b_final(ctx, hash)
|
||||
}
|
||||
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) {
|
||||
if ctx.is_keyed {
|
||||
for i := 0; i < len(ctx.padded_key); i += 1 {
|
||||
@@ -203,16 +233,14 @@ blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) {
|
||||
|
||||
blocks(ctx, ctx.x[:])
|
||||
|
||||
j := 0
|
||||
for s, _ in ctx.h[:(ctx.size - 1) / 4 + 1] {
|
||||
hash[j + 0] = byte(s >> 0)
|
||||
hash[j + 1] = byte(s >> 8)
|
||||
hash[j + 2] = byte(s >> 16)
|
||||
hash[j + 3] = byte(s >> 24)
|
||||
j += 4
|
||||
dst: [BLAKE2S_SIZE]byte
|
||||
for i := 0; i < BLAKE2S_SIZE / 4; i += 1 {
|
||||
endian.unchecked_put_u32le(dst[i * 4:], ctx.h[i])
|
||||
}
|
||||
copy(hash, dst[:])
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) {
|
||||
if ctx.is_keyed {
|
||||
for i := 0; i < len(ctx.padded_key); i += 1 {
|
||||
@@ -229,56 +257,52 @@ blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) {
|
||||
ctx.f[0] = 0xffffffffffffffff
|
||||
if ctx.is_last_node {
|
||||
ctx.f[1] = 0xffffffffffffffff
|
||||
}
|
||||
}
|
||||
|
||||
blocks(ctx, ctx.x[:])
|
||||
|
||||
j := 0
|
||||
for s, _ in ctx.h[:(ctx.size - 1) / 8 + 1] {
|
||||
hash[j + 0] = byte(s >> 0)
|
||||
hash[j + 1] = byte(s >> 8)
|
||||
hash[j + 2] = byte(s >> 16)
|
||||
hash[j + 3] = byte(s >> 24)
|
||||
hash[j + 4] = byte(s >> 32)
|
||||
hash[j + 5] = byte(s >> 40)
|
||||
hash[j + 6] = byte(s >> 48)
|
||||
hash[j + 7] = byte(s >> 56)
|
||||
j += 8
|
||||
dst: [BLAKE2B_SIZE]byte
|
||||
for i := 0; i < BLAKE2B_SIZE / 8; i += 1 {
|
||||
endian.unchecked_put_u64le(dst[i * 8:], ctx.h[i])
|
||||
}
|
||||
copy(hash, dst[:])
|
||||
}
|
||||
|
||||
@(private)
|
||||
blocks :: proc "contextless" (ctx: ^$T, p: []byte) {
|
||||
when T == Blake2s_Context {
|
||||
blake2s_blocks(ctx, p)
|
||||
}
|
||||
when T == Blake2b_Context {
|
||||
} else when T == Blake2b_Context {
|
||||
blake2b_blocks(ctx, p)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []byte) {
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 :=
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
p := p
|
||||
for len(p) >= BLAKE2S_BLOCK_SIZE {
|
||||
ctx.t[0] += BLAKE2S_BLOCK_SIZE
|
||||
if ctx.t[0] < BLAKE2S_BLOCK_SIZE {
|
||||
ctx.t[1] += 1
|
||||
}
|
||||
}
|
||||
v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7
|
||||
v8 := BLAKE2S_IV[0]
|
||||
v9 := BLAKE2S_IV[1]
|
||||
v8 := BLAKE2S_IV[0]
|
||||
v9 := BLAKE2S_IV[1]
|
||||
v10 := BLAKE2S_IV[2]
|
||||
v11 := BLAKE2S_IV[3]
|
||||
v12 := BLAKE2S_IV[4] ~ ctx.t[0]
|
||||
v13 := BLAKE2S_IV[5] ~ ctx.t[1]
|
||||
v14 := BLAKE2S_IV[6] ~ ctx.f[0]
|
||||
v15 := BLAKE2S_IV[7] ~ ctx.f[1]
|
||||
m: [16]u32
|
||||
j := 0
|
||||
|
||||
m: [16]u32 = ---
|
||||
for i := 0; i < 16; i += 1 {
|
||||
m[i] = u32(p[j]) | u32(p[j + 1]) << 8 | u32(p[j + 2]) << 16 | u32(p[j + 3]) << 24
|
||||
j += 4
|
||||
m[i] = endian.unchecked_get_u32le(p[i * 4:])
|
||||
}
|
||||
|
||||
// Round 1
|
||||
v0 += m[0]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -391,6 +415,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 2
|
||||
v0 += m[14]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -503,6 +529,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 3
|
||||
v0 += m[11]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -615,6 +643,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 4
|
||||
v0 += m[7]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -727,6 +757,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 5
|
||||
v0 += m[9]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -839,6 +871,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 6
|
||||
v0 += m[2]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -951,6 +985,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 7
|
||||
v0 += m[12]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1063,6 +1099,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 8
|
||||
v0 += m[13]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1175,6 +1213,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 9
|
||||
v0 += m[6]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1287,6 +1327,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 10
|
||||
v0 += m[10]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1399,6 +1441,7 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
h0 ~= v0 ~ v8
|
||||
h1 ~= v1 ~ v9
|
||||
h2 ~= v2 ~ v10
|
||||
@@ -1407,19 +1450,23 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
h5 ~= v5 ~ v13
|
||||
h6 ~= v6 ~ v14
|
||||
h7 ~= v7 ~ v15
|
||||
|
||||
p = p[BLAKE2S_BLOCK_SIZE:]
|
||||
}
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] =
|
||||
h0, h1, h2, h3, h4, h5, h6, h7
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []byte) {
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 :=
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
p := p
|
||||
for len(p) >= BLAKE2B_BLOCK_SIZE {
|
||||
ctx.t[0] += BLAKE2B_BLOCK_SIZE
|
||||
if ctx.t[0] < BLAKE2B_BLOCK_SIZE {
|
||||
ctx.t[1]+=1
|
||||
}
|
||||
ctx.t[1] += 1
|
||||
}
|
||||
v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7
|
||||
v8 := BLAKE2B_IV[0]
|
||||
v9 := BLAKE2B_IV[1]
|
||||
@@ -1429,13 +1476,13 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v13 := BLAKE2B_IV[5] ~ ctx.t[1]
|
||||
v14 := BLAKE2B_IV[6] ~ ctx.f[0]
|
||||
v15 := BLAKE2B_IV[7] ~ ctx.f[1]
|
||||
|
||||
m: [16]u64 = ---
|
||||
j := 0
|
||||
for i := 0; i < 16; i+=1 {
|
||||
m[i] = u64(p[j]) | u64(p[j + 1]) << 8 | u64(p[j + 2]) << 16 | u64(p[j + 3]) << 24 |
|
||||
u64(p[j + 4]) << 32 | u64(p[j + 5]) << 40 | u64(p[j + 6]) << 48 | u64(p[j + 7]) << 56
|
||||
j += 8
|
||||
for i := 0; i < 16; i += 1 {
|
||||
m[i] = endian.unchecked_get_u64le(p[i * 8:])
|
||||
}
|
||||
|
||||
// Round 1
|
||||
v0 += m[0]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1548,6 +1595,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 2
|
||||
v0 += m[14]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1660,6 +1709,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 3
|
||||
v0 += m[11]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1772,6 +1823,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 4
|
||||
v0 += m[7]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1884,6 +1937,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 5
|
||||
v0 += m[9]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1996,6 +2051,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 6
|
||||
v0 += m[2]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2108,6 +2165,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 7
|
||||
v0 += m[12]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2220,6 +2279,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 8
|
||||
v0 += m[13]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2332,6 +2393,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 9
|
||||
v0 += m[6]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2444,6 +2507,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 10
|
||||
v0 += m[10]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2556,6 +2621,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 11
|
||||
v0 += m[0]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2668,6 +2735,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 12
|
||||
v0 += m[14]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2780,6 +2849,7 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
h0 ~= v0 ~ v8
|
||||
h1 ~= v1 ~ v9
|
||||
h2 ~= v2 ~ v10
|
||||
@@ -2788,7 +2858,9 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
h5 ~= v5 ~ v13
|
||||
h6 ~= v6 ~ v14
|
||||
h7 ~= v7 ~ v15
|
||||
|
||||
p = p[BLAKE2B_BLOCK_SIZE:]
|
||||
}
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
|
||||
}
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] =
|
||||
h0, h1, h2, h3, h4, h5, h6, h7
|
||||
}
|
||||
@@ -30,6 +30,6 @@ 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.
|
||||
idiosyncratic style, and in some cases minor performance penalties.
|
||||
|
||||
[1]: https://github.com/mit-plv/fiat-crypto
|
||||
|
||||
@@ -9,14 +9,16 @@ package fiat
|
||||
u1 :: distinct u8
|
||||
i1 :: distinct i8
|
||||
|
||||
cmovznz_u64 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
|
||||
@(optimization_mode="none")
|
||||
cmovznz_u64 :: 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) {
|
||||
@(optimization_mode="none")
|
||||
cmovznz_u32 :: proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) {
|
||||
x1 := (u32(arg1) * 0xffffffff)
|
||||
x2 := ((x1 & arg3) | ((~x1) & arg2))
|
||||
out1 = x2
|
||||
|
||||
@@ -305,7 +305,8 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_assign :: #force_no_inline 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])
|
||||
@@ -596,7 +597,8 @@ fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_swap :: #force_no_inline 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package field_poly1305
|
||||
|
||||
import "core:crypto/util"
|
||||
import "core:encoding/endian"
|
||||
import "core:mem"
|
||||
|
||||
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element {
|
||||
@@ -11,7 +11,7 @@ fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_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) {
|
||||
fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte) {
|
||||
// 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.
|
||||
@@ -22,42 +22,29 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a
|
||||
|
||||
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]
|
||||
// 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.
|
||||
lo := endian.unchecked_get_u64le(arg1[0:])
|
||||
hi := endian.unchecked_get_u64le(arg1[8:])
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
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)
|
||||
endian.unchecked_put_u64le(tmp[0:], lo)
|
||||
endian.unchecked_put_u64le(tmp[8:], hi)
|
||||
|
||||
_fe_from_bytes(out1, &tmp)
|
||||
|
||||
|
||||
@@ -201,7 +201,8 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_assign :: #force_no_inline 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])
|
||||
@@ -342,7 +343,8 @@ fe_set :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: bool) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_swap :: #force_no_inline 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
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
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,183 @@
|
||||
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 "core:math/bits"
|
||||
|
||||
ROUNDS :: 24
|
||||
|
||||
Sha3_Context :: struct {
|
||||
st: struct #raw_union {
|
||||
b: [200]u8,
|
||||
q: [25]u64,
|
||||
},
|
||||
pt: int,
|
||||
rsiz: int,
|
||||
mdlen: int,
|
||||
is_keccak: bool,
|
||||
|
||||
is_initialized: bool,
|
||||
is_finalized: bool, // For SHAKE (unlimited squeeze is allowed)
|
||||
}
|
||||
|
||||
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 := [?]int {
|
||||
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 {
|
||||
for i = 0; i < 25; i += 1 {
|
||||
st[i] = bits.byte_swap(st[i])
|
||||
}
|
||||
}
|
||||
|
||||
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] ~ bits.rotate_left64(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] = bits.rotate_left64(t, 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 {
|
||||
st[i] = bits.byte_swap(st[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init :: proc(c: ^Sha3_Context) {
|
||||
for i := 0; i < 25; i += 1 {
|
||||
c.st.q[i] = 0
|
||||
}
|
||||
c.rsiz = 200 - 2 * c.mdlen
|
||||
c.pt = 0
|
||||
|
||||
c.is_initialized = true
|
||||
c.is_finalized = false
|
||||
}
|
||||
|
||||
update :: proc(c: ^Sha3_Context, data: []byte) {
|
||||
assert(c.is_initialized)
|
||||
assert(!c.is_finalized)
|
||||
|
||||
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(c: ^Sha3_Context, hash: []byte) {
|
||||
assert(c.is_initialized)
|
||||
|
||||
if len(hash) < c.mdlen {
|
||||
if c.is_keccak {
|
||||
panic("crypto/keccac: invalid destination digest size")
|
||||
}
|
||||
panic("crypto/sha3: invalid destination digest size")
|
||||
}
|
||||
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]
|
||||
}
|
||||
|
||||
c.is_initialized = false // No more absorb, no more squeeze.
|
||||
}
|
||||
|
||||
shake_xof :: proc(c: ^Sha3_Context) {
|
||||
assert(c.is_initialized)
|
||||
assert(!c.is_finalized)
|
||||
|
||||
c.st.b[c.pt] ~= 0x1F
|
||||
c.st.b[c.rsiz - 1] ~= 0x80
|
||||
keccakf(&c.st.q)
|
||||
c.pt = 0
|
||||
|
||||
c.is_finalized = true // No more absorb, unlimited squeeze.
|
||||
}
|
||||
|
||||
shake_out :: proc(c: ^Sha3_Context, hash: []byte) {
|
||||
assert(c.is_initialized)
|
||||
assert(c.is_finalized)
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
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)])
|
||||
}
|
||||
@@ -1,726 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -7,12 +7,12 @@ package blake2b
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the BLAKE2B hashing algorithm.
|
||||
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
|
||||
Interface for the BLAKE2b hashing algorithm.
|
||||
BLAKE2b and BLAKE2s share the implementation in the _blake2 package.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
import "core:os"
|
||||
|
||||
import "../_blake2"
|
||||
|
||||
@@ -25,103 +25,103 @@ 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))
|
||||
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: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
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(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)
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
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: _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: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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,
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Blake2b_Context :: _blake2.Blake2b_Context
|
||||
Context :: _blake2.Blake2b_Context
|
||||
|
||||
init :: proc(ctx: ^_blake2.Blake2b_Context) {
|
||||
_blake2.init(ctx)
|
||||
init :: proc(ctx: ^Context) {
|
||||
_blake2.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ package blake2s
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the BLAKE2S hashing algorithm.
|
||||
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
|
||||
Interface for the BLAKE2s hashing algorithm.
|
||||
BLAKE2s and BLAKE2b share the implementation in the _blake2 package.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
import "core:os"
|
||||
|
||||
import "../_blake2"
|
||||
|
||||
@@ -25,103 +25,103 @@ 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))
|
||||
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: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
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(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)
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
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: _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: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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,
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Blake2s_Context :: _blake2.Blake2b_Context
|
||||
Context :: _blake2.Blake2s_Context
|
||||
|
||||
init :: proc(ctx: ^_blake2.Blake2s_Context) {
|
||||
_blake2.init(ctx)
|
||||
init :: proc(ctx: ^Context) {
|
||||
_blake2.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
}
|
||||
|
||||
+145
-180
@@ -1,6 +1,6 @@
|
||||
package chacha20
|
||||
|
||||
import "core:crypto/util"
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
|
||||
@@ -8,15 +8,23 @@ KEY_SIZE :: 32
|
||||
NONCE_SIZE :: 12
|
||||
XNONCE_SIZE :: 24
|
||||
|
||||
@(private)
|
||||
_MAX_CTR_IETF :: 0xffffffff
|
||||
|
||||
@(private)
|
||||
_BLOCK_SIZE :: 64
|
||||
@(private)
|
||||
_STATE_SIZE_U32 :: 16
|
||||
@(private)
|
||||
_ROUNDS :: 20
|
||||
|
||||
@(private)
|
||||
_SIGMA_0 : u32 : 0x61707865
|
||||
@(private)
|
||||
_SIGMA_1 : u32 : 0x3320646e
|
||||
@(private)
|
||||
_SIGMA_2 : u32 : 0x79622d32
|
||||
@(private)
|
||||
_SIGMA_3 : u32 : 0x6b206574
|
||||
|
||||
Context :: struct {
|
||||
@@ -52,23 +60,23 @@ init :: proc (ctx: ^Context, key, nonce: []byte) {
|
||||
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[4] = endian.unchecked_get_u32le(k[0:4])
|
||||
ctx._s[5] = endian.unchecked_get_u32le(k[4:8])
|
||||
ctx._s[6] = endian.unchecked_get_u32le(k[8:12])
|
||||
ctx._s[7] = endian.unchecked_get_u32le(k[12:16])
|
||||
ctx._s[8] = endian.unchecked_get_u32le(k[16:20])
|
||||
ctx._s[9] = endian.unchecked_get_u32le(k[20:24])
|
||||
ctx._s[10] = endian.unchecked_get_u32le(k[24:28])
|
||||
ctx._s[11] = endian.unchecked_get_u32le(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])
|
||||
ctx._s[13] = endian.unchecked_get_u32le(n[0:4])
|
||||
ctx._s[14] = endian.unchecked_get_u32le(n[4:8])
|
||||
ctx._s[15] = endian.unchecked_get_u32le(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])
|
||||
ctx._s[14] = endian.unchecked_get_u32le(n[0:4])
|
||||
ctx._s[15] = endian.unchecked_get_u32le(n[4:8])
|
||||
|
||||
// The sub-key is stored in the keystream buffer. While
|
||||
// this will be overwritten in most circumstances, explicitly
|
||||
@@ -179,6 +187,7 @@ reset :: proc (ctx: ^Context) {
|
||||
ctx._is_initialized = false
|
||||
}
|
||||
|
||||
@(private)
|
||||
_do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per nonce.
|
||||
//
|
||||
@@ -212,114 +221,114 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
}
|
||||
|
||||
x0 += _SIGMA_0
|
||||
@@ -343,93 +352,48 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// 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.
|
||||
// In the meantime:
|
||||
// - The caller(s) ensure that src/dst are valid.
|
||||
// - The compiler knows if the target is picky about alignment.
|
||||
|
||||
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])
|
||||
#no_bounds_check {
|
||||
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
|
||||
endian.unchecked_put_u32le(dst[0:4], endian.unchecked_get_u32le(src[0:4]) ~ x0)
|
||||
endian.unchecked_put_u32le(dst[4:8], endian.unchecked_get_u32le(src[4:8]) ~ x1)
|
||||
endian.unchecked_put_u32le(dst[8:12], endian.unchecked_get_u32le(src[8:12]) ~ x2)
|
||||
endian.unchecked_put_u32le(dst[12:16], endian.unchecked_get_u32le(src[12:16]) ~ x3)
|
||||
endian.unchecked_put_u32le(dst[16:20], endian.unchecked_get_u32le(src[16:20]) ~ x4)
|
||||
endian.unchecked_put_u32le(dst[20:24], endian.unchecked_get_u32le(src[20:24]) ~ x5)
|
||||
endian.unchecked_put_u32le(dst[24:28], endian.unchecked_get_u32le(src[24:28]) ~ x6)
|
||||
endian.unchecked_put_u32le(dst[28:32], endian.unchecked_get_u32le(src[28:32]) ~ x7)
|
||||
endian.unchecked_put_u32le(dst[32:36], endian.unchecked_get_u32le(src[32:36]) ~ x8)
|
||||
endian.unchecked_put_u32le(dst[36:40], endian.unchecked_get_u32le(src[36:40]) ~ x9)
|
||||
endian.unchecked_put_u32le(dst[40:44], endian.unchecked_get_u32le(src[40:44]) ~ x10)
|
||||
endian.unchecked_put_u32le(dst[44:48], endian.unchecked_get_u32le(src[44:48]) ~ x11)
|
||||
endian.unchecked_put_u32le(dst[48:52], endian.unchecked_get_u32le(src[48:52]) ~ x12)
|
||||
endian.unchecked_put_u32le(dst[52:56], endian.unchecked_get_u32le(src[52:56]) ~ x13)
|
||||
endian.unchecked_put_u32le(dst[56:60], endian.unchecked_get_u32le(src[56:60]) ~ x14)
|
||||
endian.unchecked_put_u32le(dst[60:64], endian.unchecked_get_u32le(src[60:64]) ~ 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
|
||||
endian.unchecked_put_u32le(dst[0:4], x0)
|
||||
endian.unchecked_put_u32le(dst[4:8], x1)
|
||||
endian.unchecked_put_u32le(dst[8:12], x2)
|
||||
endian.unchecked_put_u32le(dst[12:16], x3)
|
||||
endian.unchecked_put_u32le(dst[16:20], x4)
|
||||
endian.unchecked_put_u32le(dst[20:24], x5)
|
||||
endian.unchecked_put_u32le(dst[24:28], x6)
|
||||
endian.unchecked_put_u32le(dst[28:32], x7)
|
||||
endian.unchecked_put_u32le(dst[32:36], x8)
|
||||
endian.unchecked_put_u32le(dst[36:40], x9)
|
||||
endian.unchecked_put_u32le(dst[40:44], x10)
|
||||
endian.unchecked_put_u32le(dst[44:48], x11)
|
||||
endian.unchecked_put_u32le(dst[48:52], x12)
|
||||
endian.unchecked_put_u32le(dst[52:56], x13)
|
||||
endian.unchecked_put_u32le(dst[56:60], x14)
|
||||
endian.unchecked_put_u32le(dst[60:64], 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
|
||||
@@ -441,141 +405,142 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
}
|
||||
}
|
||||
|
||||
_hchacha20 :: proc (dst, key, nonce: []byte) {
|
||||
@(private)
|
||||
_hchacha20 :: proc "contextless" (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])
|
||||
x4 := endian.unchecked_get_u32le(key[0:4])
|
||||
x5 := endian.unchecked_get_u32le(key[4:8])
|
||||
x6 := endian.unchecked_get_u32le(key[8:12])
|
||||
x7 := endian.unchecked_get_u32le(key[12:16])
|
||||
x8 := endian.unchecked_get_u32le(key[16:20])
|
||||
x9 := endian.unchecked_get_u32le(key[20:24])
|
||||
x10 := endian.unchecked_get_u32le(key[24:28])
|
||||
x11 := endian.unchecked_get_u32le(key[28:32])
|
||||
x12 := endian.unchecked_get_u32le(nonce[0:4])
|
||||
x13 := endian.unchecked_get_u32le(nonce[4:8])
|
||||
x14 := endian.unchecked_get_u32le(nonce[8:12])
|
||||
x15 := endian.unchecked_get_u32le(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)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(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)
|
||||
endian.unchecked_put_u32le(dst[0:4], x0)
|
||||
endian.unchecked_put_u32le(dst[4:8], x1)
|
||||
endian.unchecked_put_u32le(dst[8:12], x2)
|
||||
endian.unchecked_put_u32le(dst[12:16], x3)
|
||||
endian.unchecked_put_u32le(dst[16:20], x12)
|
||||
endian.unchecked_put_u32le(dst[20:24], x13)
|
||||
endian.unchecked_put_u32le(dst[24:28], x14)
|
||||
endian.unchecked_put_u32le(dst[28:32], x15)
|
||||
}
|
||||
|
||||
@@ -3,15 +3,17 @@ package chacha20poly1305
|
||||
import "core:crypto"
|
||||
import "core:crypto/chacha20"
|
||||
import "core:crypto/poly1305"
|
||||
import "core:crypto/util"
|
||||
import "core:encoding/endian"
|
||||
import "core:mem"
|
||||
|
||||
KEY_SIZE :: chacha20.KEY_SIZE
|
||||
NONCE_SIZE :: chacha20.NONCE_SIZE
|
||||
TAG_SIZE :: poly1305.TAG_SIZE
|
||||
|
||||
@(private)
|
||||
_P_MAX :: 64 * 0xffffffff // 64 * (2^32-1)
|
||||
|
||||
@(private)
|
||||
_validate_common_slice_sizes :: proc (tag, key, nonce, aad, text: []byte) {
|
||||
if len(tag) != TAG_SIZE {
|
||||
panic("crypto/chacha20poly1305: invalid destination tag size")
|
||||
@@ -37,7 +39,10 @@ _validate_common_slice_sizes :: proc (tag, key, nonce, aad, text: []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_PAD: [16]byte
|
||||
|
||||
@(private)
|
||||
_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])
|
||||
@@ -82,8 +87,8 @@ encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
|
||||
// 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))
|
||||
endian.unchecked_put_u64le(l_buf[0:8], u64(aad_len))
|
||||
endian.unchecked_put_u64le(l_buf[8:16], u64(ciphertext_len))
|
||||
poly1305.update(&mac_ctx, l_buf)
|
||||
|
||||
// tag = poly1305_mac(mac_data, otk)
|
||||
@@ -123,8 +128,8 @@ decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool {
|
||||
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))
|
||||
endian.unchecked_put_u64le(l_buf[0:8], u64(aad_len))
|
||||
endian.unchecked_put_u64le(l_buf[8:16], u64(ciphertext_len))
|
||||
poly1305.update(&mac_ctx, l_buf)
|
||||
|
||||
// tag = poly1305_mac(mac_data, otk)
|
||||
|
||||
@@ -26,6 +26,7 @@ compare_constant_time :: proc "contextless" (a, b: []byte) -> int {
|
||||
//
|
||||
// The execution time of this routine is constant regardless of the
|
||||
// contents of the memory being compared.
|
||||
@(optimization_mode="none")
|
||||
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)
|
||||
|
||||
@@ -1,382 +0,0 @@
|
||||
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]
|
||||
}
|
||||
@@ -1,653 +0,0 @@
|
||||
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
@@ -1,584 +0,0 @@
|
||||
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]
|
||||
}
|
||||
}
|
||||
@@ -1,374 +0,0 @@
|
||||
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,10 @@
|
||||
# crypto/legacy
|
||||
|
||||
These are algorithms that are shipped solely for the purpose of
|
||||
interoperability with legacy systems. The use of these packages in
|
||||
any other capacity is discouraged, especially those that are known
|
||||
to be broken.
|
||||
|
||||
- keccak - The draft version of the algorithm that became SHA-3
|
||||
- MD5 - Broken (https://eprint.iacr.org/2005/075)
|
||||
- SHA-1 - Broken (https://eprint.iacr.org/2017/190)
|
||||
@@ -0,0 +1,377 @@
|
||||
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:io"
|
||||
import "core:os"
|
||||
|
||||
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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
ctx.is_keccak = 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) {
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
ctx.is_keccak = 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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
ctx.is_keccak = true
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
ctx.is_keccak = 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) {
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
ctx.is_keccak = 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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
ctx.is_keccak = true
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
ctx.is_keccak = 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) {
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
ctx.is_keccak = 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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
ctx.is_keccak = true
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
ctx.is_keccak = true
|
||||
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) {
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
ctx.is_keccak = true
|
||||
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: Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
ctx.is_keccak = true
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
*/
|
||||
|
||||
Context :: _sha3.Sha3_Context
|
||||
|
||||
init :: proc(ctx: ^Context) {
|
||||
ctx.is_keccak = true
|
||||
_sha3.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_sha3.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
_sha3.final(ctx, hash)
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
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:encoding/endian"
|
||||
import "core:io"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
|
||||
/*
|
||||
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: 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) {
|
||||
ctx: 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: Context
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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: ^Context) {
|
||||
ctx.state[0] = 0x67452301
|
||||
ctx.state[1] = 0xefcdab89
|
||||
ctx.state[2] = 0x98badcfe
|
||||
ctx.state[3] = 0x10325476
|
||||
|
||||
ctx.bitlen = 0
|
||||
ctx.datalen = 0
|
||||
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
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: ^Context, hash: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
if len(hash) < DIGEST_SIZE {
|
||||
panic("crypto/md5: invalid destination digest size")
|
||||
}
|
||||
|
||||
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)
|
||||
endian.unchecked_put_u64le(ctx.data[56:], ctx.bitlen)
|
||||
transform(ctx, ctx.data[:])
|
||||
|
||||
for i = 0; i < DIGEST_SIZE / 4; i += 1 {
|
||||
endian.unchecked_put_u32le(hash[i * 4:], ctx.state[i])
|
||||
}
|
||||
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
/*
|
||||
MD5 implementation
|
||||
*/
|
||||
|
||||
BLOCK_SIZE :: 64
|
||||
|
||||
Context :: struct {
|
||||
data: [BLOCK_SIZE]byte,
|
||||
state: [4]u32,
|
||||
bitlen: u64,
|
||||
datalen: u32,
|
||||
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
/*
|
||||
@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.
|
||||
*/
|
||||
|
||||
@(private)
|
||||
FF :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + bits.rotate_left32(a + ((b & c) | (~b & d)) + m + t, s)
|
||||
}
|
||||
|
||||
@(private)
|
||||
GG :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + bits.rotate_left32(a + ((b & d) | (c & ~d)) + m + t, s)
|
||||
}
|
||||
|
||||
@(private)
|
||||
HH :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + bits.rotate_left32(a + (b ~ c ~ d) + m + t, s)
|
||||
}
|
||||
|
||||
@(private)
|
||||
II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
|
||||
return b + bits.rotate_left32(a + (c ~ (b | ~d)) + m + t, s)
|
||||
}
|
||||
|
||||
@(private)
|
||||
transform :: proc "contextless" (ctx: ^Context, data: []byte) {
|
||||
m: [DIGEST_SIZE]u32
|
||||
|
||||
for i := 0; i < DIGEST_SIZE; i += 1 {
|
||||
m[i] = endian.unchecked_get_u32le(data[i * 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,252 @@
|
||||
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:encoding/endian"
|
||||
import "core:io"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
|
||||
/*
|
||||
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: 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) {
|
||||
ctx: 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: Context
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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: ^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
|
||||
|
||||
ctx.datalen = 0
|
||||
ctx.bitlen = 0
|
||||
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
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: ^Context, hash: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
if len(hash) < DIGEST_SIZE {
|
||||
panic("crypto/sha1: invalid destination digest size")
|
||||
}
|
||||
|
||||
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)
|
||||
endian.unchecked_put_u64be(ctx.data[56:], ctx.bitlen)
|
||||
transform(ctx, ctx.data[:])
|
||||
|
||||
for i = 0; i < DIGEST_SIZE / 4; i += 1 {
|
||||
endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i])
|
||||
}
|
||||
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
/*
|
||||
SHA1 implementation
|
||||
*/
|
||||
|
||||
BLOCK_SIZE :: 64
|
||||
|
||||
Context :: struct {
|
||||
data: [BLOCK_SIZE]byte,
|
||||
datalen: u32,
|
||||
bitlen: u64,
|
||||
state: [5]u32,
|
||||
k: [4]u32,
|
||||
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
@(private)
|
||||
transform :: proc "contextless" (ctx: ^Context, data: []byte) {
|
||||
a, b, c, d, e, i, t: u32
|
||||
m: [80]u32
|
||||
|
||||
for i = 0; i < 16; i += 1 {
|
||||
m[i] = endian.unchecked_get_u32be(data[i * 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 = bits.rotate_left32(a, 5) + ((b & c) ~ (~b & d)) + e + ctx.k[0] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = bits.rotate_left32(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
}
|
||||
for i < 40 {
|
||||
t = bits.rotate_left32(a, 5) + (b ~ c ~ d) + e + ctx.k[1] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = bits.rotate_left32(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
i += 1
|
||||
}
|
||||
for i < 60 {
|
||||
t = bits.rotate_left32(a, 5) + ((b & c) ~ (b & d) ~ (c & d)) + e + ctx.k[2] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = bits.rotate_left32(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
i += 1
|
||||
}
|
||||
for i < 80 {
|
||||
t = bits.rotate_left32(a, 5) + (b ~ c ~ d) + e + ctx.k[3] + m[i]
|
||||
e = d
|
||||
d = c
|
||||
c = bits.rotate_left32(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
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
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]
|
||||
}
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
package poly1305
|
||||
|
||||
import "core:crypto"
|
||||
import "core:crypto/util"
|
||||
import field "core:crypto/_fiat/field_poly1305"
|
||||
import "core:encoding/endian"
|
||||
import "core:mem"
|
||||
|
||||
KEY_SIZE :: 32
|
||||
TAG_SIZE :: 16
|
||||
|
||||
@(private)
|
||||
_BLOCK_SIZE :: 16
|
||||
|
||||
sum :: proc (dst, msg, key: []byte) {
|
||||
@@ -51,8 +52,8 @@ init :: proc (ctx: ^Context, key: []byte) {
|
||||
|
||||
// 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
|
||||
tmp_lo := endian.unchecked_get_u64le(key[0:]) & 0x0ffffffc0fffffff
|
||||
tmp_hi := endian.unchecked_get_u64le(key[8:]) & 0xffffffc0ffffffc
|
||||
field.fe_from_u64s(&ctx._r, tmp_lo, tmp_hi)
|
||||
|
||||
// s = le_bytes_to_num(key[16..31])
|
||||
@@ -141,6 +142,7 @@ reset :: proc (ctx: ^Context) {
|
||||
ctx._is_initialized = false
|
||||
}
|
||||
|
||||
@(private)
|
||||
_blocks :: proc (ctx: ^Context, msg: []byte, final := false) {
|
||||
n: field.Tight_Field_Element = ---
|
||||
final_byte := byte(!final)
|
||||
@@ -149,7 +151,7 @@ _blocks :: proc (ctx: ^Context, msg: []byte, final := false) {
|
||||
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)
|
||||
field.fe_from_bytes(&n, data[:_BLOCK_SIZE], final_byte)
|
||||
|
||||
// a += n
|
||||
field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &n) // _a unreduced
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package crypto
|
||||
|
||||
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows {
|
||||
_rand_bytes :: proc (dst: []byte) {
|
||||
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows && ODIN_OS != .JS {
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
unimplemented("crypto: rand_bytes not supported on this OS")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package crypto
|
||||
|
||||
foreign import "odin_env"
|
||||
foreign odin_env {
|
||||
@(link_name = "rand_bytes")
|
||||
env_rand_bytes :: proc "contextless" (buf: []byte) ---
|
||||
}
|
||||
|
||||
_MAX_PER_CALL_BYTES :: 65536 // 64kiB
|
||||
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
dst := dst
|
||||
|
||||
for len(dst) > 0 {
|
||||
to_read := min(len(dst), _MAX_PER_CALL_BYTES)
|
||||
env_rand_bytes(dst[:to_read])
|
||||
|
||||
dst = dst[to_read:]
|
||||
}
|
||||
}
|
||||
+21
-22
@@ -1,8 +1,8 @@
|
||||
package crypto
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:sys/unix"
|
||||
|
||||
import "core:sys/linux"
|
||||
|
||||
_MAX_PER_CALL_BYTES :: 33554431 // 2^25 - 1
|
||||
|
||||
@@ -12,26 +12,25 @@ _rand_bytes :: proc (dst: []byte) {
|
||||
|
||||
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))
|
||||
}
|
||||
n_read, errno := linux.getrandom(dst[:to_read], {})
|
||||
#partial switch errno {
|
||||
case .NONE:
|
||||
// Do nothing
|
||||
case .EINTR:
|
||||
// Call interupted by a signal handler, just retry the
|
||||
// request.
|
||||
continue
|
||||
case .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: %v", errno))
|
||||
}
|
||||
|
||||
l -= ret
|
||||
dst = dst[ret:]
|
||||
l -= n_read
|
||||
dst = dst[n_read:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,919 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
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
|
||||
}
|
||||
+533
-411
File diff suppressed because it is too large
Load Diff
+188
-184
@@ -11,8 +11,8 @@ package sha3
|
||||
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 "core:os"
|
||||
|
||||
import "../_sha3"
|
||||
|
||||
@@ -28,333 +28,337 @@ 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))
|
||||
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: [DIGEST_SIZE_224]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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(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)
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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: _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: [DIGEST_SIZE_224]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_224
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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_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))
|
||||
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: [DIGEST_SIZE_256]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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(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)
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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: _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: [DIGEST_SIZE_256]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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_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))
|
||||
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: [DIGEST_SIZE_384]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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(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)
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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: _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: [DIGEST_SIZE_384]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_384
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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_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))
|
||||
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: [DIGEST_SIZE_512]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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(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)
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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: _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: [DIGEST_SIZE_512]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_512
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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,
|
||||
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
|
||||
Context :: _sha3.Sha3_Context
|
||||
|
||||
init :: proc(ctx: ^_sha3.Sha3_Context) {
|
||||
_sha3.init(ctx)
|
||||
init :: proc(ctx: ^Context) {
|
||||
_sha3.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
|
||||
_sha3.update(ctx, data)
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_sha3.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
|
||||
_sha3.final(ctx, hash)
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
_sha3.final(ctx, hash)
|
||||
}
|
||||
|
||||
+102
-103
@@ -9,10 +9,13 @@ package shake
|
||||
|
||||
Interface for the SHAKE hashing algorithm.
|
||||
The SHA3 functionality can be found in package sha3.
|
||||
|
||||
TODO: This should provide an incremental squeeze interface, in addition
|
||||
to the one-shot final call.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
import "core:os"
|
||||
|
||||
import "../_sha3"
|
||||
|
||||
@@ -26,182 +29,178 @@ 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))
|
||||
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: [DIGEST_SIZE_128]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_128
|
||||
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(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)
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_128
|
||||
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: _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: [DIGEST_SIZE_128]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_128
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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_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))
|
||||
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: [DIGEST_SIZE_256]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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(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)
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_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: _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: [DIGEST_SIZE_256]byte
|
||||
ctx: Context
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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_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
|
||||
Context :: _sha3.Sha3_Context
|
||||
|
||||
init :: proc(ctx: ^_sha3.Sha3_Context) {
|
||||
_sha3.init(ctx)
|
||||
init :: proc(ctx: ^Context) {
|
||||
_sha3.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
|
||||
_sha3.update(ctx, data)
|
||||
update :: proc(ctx: ^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[:])
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
_sha3.shake_xof(ctx)
|
||||
_sha3.shake_out(ctx, hash[:])
|
||||
}
|
||||
|
||||
+208
-180
@@ -13,202 +13,200 @@ package siphash
|
||||
*/
|
||||
|
||||
import "core:crypto"
|
||||
import "core:crypto/util"
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
KEY_SIZE :: 16
|
||||
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))
|
||||
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_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(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)
|
||||
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,
|
||||
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
|
||||
// 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_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
|
||||
// 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_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,
|
||||
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))
|
||||
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_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(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)
|
||||
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_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 :: 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_bytes_to_buffer :: sum_bytes_to_buffer_2_4
|
||||
sum :: proc {
|
||||
sum_string,
|
||||
sum_bytes,
|
||||
sum_string_to_buffer,
|
||||
sum_bytes_to_buffer,
|
||||
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
|
||||
// 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_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
|
||||
// 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_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_2_4,
|
||||
verify_u64_2_4,
|
||||
}
|
||||
|
||||
verify_bytes :: verify_bytes_2_4
|
||||
verify_u64 :: verify_u64_2_4
|
||||
verify_u64 :: verify_u64_2_4
|
||||
verify :: proc {
|
||||
verify_bytes,
|
||||
verify_u64,
|
||||
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))
|
||||
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_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(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)
|
||||
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,
|
||||
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
|
||||
// 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_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
|
||||
// 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_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,
|
||||
verify_bytes_4_8,
|
||||
verify_u64_4_8,
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -216,120 +214,150 @@ verify_4_8 :: proc {
|
||||
*/
|
||||
|
||||
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
|
||||
if len(key) != KEY_SIZE {
|
||||
panic("crypto/siphash; invalid key size")
|
||||
}
|
||||
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)
|
||||
if !is_valid_setting {
|
||||
panic("crypto/siphash: incorrect rounds set up")
|
||||
}
|
||||
ctx.k0 = endian.unchecked_get_u64le(key[:8])
|
||||
ctx.k1 = endian.unchecked_get_u64le(key[8:])
|
||||
ctx.v0 = 0x736f6d6570736575 ~ ctx.k0
|
||||
ctx.v1 = 0x646f72616e646f6d ~ ctx.k1
|
||||
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
||||
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
||||
|
||||
ctx.last_block = 0
|
||||
ctx.total_length = 0
|
||||
|
||||
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
|
||||
assert(ctx.is_initialized, "crypto/siphash: context is not initialized")
|
||||
|
||||
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
|
||||
}
|
||||
data := data
|
||||
ctx.total_length += len(data)
|
||||
if ctx.last_block > 0 {
|
||||
n := copy(ctx.buf[ctx.last_block:], data)
|
||||
ctx.last_block += n
|
||||
if ctx.last_block == BLOCK_SIZE {
|
||||
block(ctx, ctx.buf[:])
|
||||
ctx.last_block = 0
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= BLOCK_SIZE {
|
||||
n := len(data) &~ (BLOCK_SIZE - 1)
|
||||
block(ctx, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) > 0 {
|
||||
ctx.last_block = copy(ctx.buf[:], data)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
assert(ctx.is_initialized, "crypto/siphash: context is not initialized")
|
||||
|
||||
ctx.v3 ~= m
|
||||
tmp: [BLOCK_SIZE]byte
|
||||
copy(tmp[:], ctx.buf[:ctx.last_block])
|
||||
tmp[7] = byte(ctx.total_length & 0xff)
|
||||
block(ctx, tmp[:])
|
||||
|
||||
for _ in 0..<ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
ctx.v2 ~= 0xff
|
||||
|
||||
ctx.v0 ~= m
|
||||
ctx.v2 ~= 0xff
|
||||
for _ in 0 ..< ctx.d_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
for _ in 0..<ctx.d_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
dst^ = ctx.v0 ~ ctx.v1 ~ ctx.v2 ~ ctx.v3
|
||||
|
||||
dst^ = ctx.v0 ~ ctx.v1 ~ ctx.v2 ~ ctx.v3
|
||||
|
||||
reset(ctx)
|
||||
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
|
||||
ctx.k0, ctx.k1 = 0, 0
|
||||
ctx.v0, ctx.v1 = 0, 0
|
||||
ctx.v2, ctx.v3 = 0, 0
|
||||
ctx.last_block = 0
|
||||
ctx.total_length = 0
|
||||
ctx.c_rounds = 0
|
||||
ctx.d_rounds = 0
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
BLOCK_SIZE :: 8
|
||||
|
||||
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,
|
||||
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: [BLOCK_SIZE]byte, // Provided data
|
||||
last_block: int, // Offset from the last block
|
||||
total_length: int,
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
@(private)
|
||||
block :: proc "contextless" (ctx: ^Context, buf: []byte) {
|
||||
buf := buf
|
||||
|
||||
for len(buf) >= BLOCK_SIZE {
|
||||
m := endian.unchecked_get_u64le(buf)
|
||||
|
||||
ctx.v3 ~= m
|
||||
for _ in 0 ..< ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
|
||||
buf = buf[BLOCK_SIZE:]
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
||||
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
||||
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)
|
||||
@(private)
|
||||
_collect_output :: #force_inline proc(dst: []byte, hash: u64) {
|
||||
if len(dst) < DIGEST_SIZE {
|
||||
panic("crypto/siphash: invalid tag size")
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_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)
|
||||
ctx.v0 += ctx.v1
|
||||
ctx.v1 = bits.rotate_left64(ctx.v1, 13)
|
||||
ctx.v1 ~= ctx.v0
|
||||
ctx.v0 = bits.rotate_left64(ctx.v0, 32)
|
||||
ctx.v2 += ctx.v3
|
||||
ctx.v3 = bits.rotate_left64(ctx.v3, 16)
|
||||
ctx.v3 ~= ctx.v2
|
||||
ctx.v0 += ctx.v3
|
||||
ctx.v3 = bits.rotate_left64(ctx.v3, 21)
|
||||
ctx.v3 ~= ctx.v0
|
||||
ctx.v2 += ctx.v1
|
||||
ctx.v1 = bits.rotate_left64(ctx.v1, 17)
|
||||
ctx.v1 ~= ctx.v2
|
||||
ctx.v2 = bits.rotate_left64(ctx.v2, 32)
|
||||
}
|
||||
|
||||
+187
-158
@@ -10,10 +10,10 @@ package sm3
|
||||
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:encoding/endian"
|
||||
import "core:io"
|
||||
|
||||
import "../util"
|
||||
import "core:math/bits"
|
||||
import "core:os"
|
||||
|
||||
/*
|
||||
High level API
|
||||
@@ -24,227 +24,256 @@ 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))
|
||||
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: [DIGEST_SIZE]byte
|
||||
ctx: 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(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)
|
||||
ctx: 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: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, 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
|
||||
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,
|
||||
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]
|
||||
init :: proc(ctx: ^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]
|
||||
|
||||
ctx.length = 0
|
||||
ctx.bitlength = 0
|
||||
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Sm3_Context, data: []byte) {
|
||||
data := data
|
||||
ctx.length += u64(len(data))
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
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[:]))
|
||||
}
|
||||
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 == BLOCK_SIZE {
|
||||
block(ctx, ctx.x[:])
|
||||
ctx.bitlength = 0
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= BLOCK_SIZE {
|
||||
n := len(data) &~ (BLOCK_SIZE - 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
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
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])
|
||||
}
|
||||
if len(hash) < DIGEST_SIZE {
|
||||
panic("crypto/sm3: invalid destination digest size")
|
||||
}
|
||||
|
||||
length <<= 3
|
||||
util.PUT_U64_BE(pad[:], length)
|
||||
update(ctx, pad[0: 8])
|
||||
assert(ctx.bitlength == 0)
|
||||
length := ctx.length
|
||||
|
||||
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])
|
||||
pad: [BLOCK_SIZE]byte
|
||||
pad[0] = 0x80
|
||||
if length % BLOCK_SIZE < 56 {
|
||||
update(ctx, pad[0:56 - length % BLOCK_SIZE])
|
||||
} else {
|
||||
update(ctx, pad[0:BLOCK_SIZE + 56 - length % BLOCK_SIZE])
|
||||
}
|
||||
|
||||
length <<= 3
|
||||
endian.unchecked_put_u64be(pad[:], length)
|
||||
update(ctx, pad[0:8])
|
||||
assert(ctx.bitlength == 0)
|
||||
|
||||
for i := 0; i < DIGEST_SIZE / 4; i += 1 {
|
||||
endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i])
|
||||
}
|
||||
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
/*
|
||||
SM3 implementation
|
||||
*/
|
||||
|
||||
Sm3_Context :: struct {
|
||||
state: [8]u32,
|
||||
x: [64]byte,
|
||||
bitlength: u64,
|
||||
length: u64,
|
||||
BLOCK_SIZE :: 64
|
||||
|
||||
Context :: struct {
|
||||
state: [8]u32,
|
||||
x: [BLOCK_SIZE]byte,
|
||||
bitlength: u64,
|
||||
length: u64,
|
||||
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
@(private)
|
||||
IV := [8]u32 {
|
||||
0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600,
|
||||
0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e,
|
||||
0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600,
|
||||
0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e,
|
||||
}
|
||||
|
||||
block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) {
|
||||
buf := buf
|
||||
@(private)
|
||||
block :: proc "contextless" (ctx: ^Context, buf: []byte) {
|
||||
buf := buf
|
||||
|
||||
w: [68]u32
|
||||
wp: [64]u32
|
||||
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]
|
||||
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]
|
||||
}
|
||||
for len(buf) >= BLOCK_SIZE {
|
||||
for i := 0; i < 16; i += 1 {
|
||||
w[i] = endian.unchecked_get_u32be(buf[i * 4:])
|
||||
}
|
||||
for i := 16; i < 68; i += 1 {
|
||||
p1v := w[i - 16] ~ w[i - 9] ~ bits.rotate_left32(w[i - 3], 15)
|
||||
// @note(zh): inlined P1
|
||||
w[i] =
|
||||
p1v ~
|
||||
bits.rotate_left32(p1v, 15) ~
|
||||
bits.rotate_left32(p1v, 23) ~
|
||||
bits.rotate_left32(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
|
||||
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
|
||||
for i := 0; i < 16; i += 1 {
|
||||
v1 := bits.rotate_left32(u32(a), 12)
|
||||
ss1 := bits.rotate_left32(v1 + u32(e) + bits.rotate_left32(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]
|
||||
// @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
|
||||
}
|
||||
a, b, c, d = tt1, a, bits.rotate_left32(u32(b), 9), c
|
||||
// @note(zh): inlined P0
|
||||
e, f, g, h =
|
||||
(tt2 ~ bits.rotate_left32(tt2, 9) ~ bits.rotate_left32(tt2, 17)),
|
||||
e,
|
||||
bits.rotate_left32(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
|
||||
for i := 16; i < 64; i += 1 {
|
||||
v := bits.rotate_left32(u32(a), 12)
|
||||
ss1 := bits.rotate_left32(v + u32(e) + bits.rotate_left32(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]
|
||||
// @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
|
||||
}
|
||||
a, b, c, d = tt1, a, bits.rotate_left32(u32(b), 9), c
|
||||
// @note(zh): inlined P0
|
||||
e, f, g, h =
|
||||
(tt2 ~ bits.rotate_left32(tt2, 9) ~ bits.rotate_left32(tt2, 17)),
|
||||
e,
|
||||
bits.rotate_left32(u32(f), 19),
|
||||
g
|
||||
}
|
||||
|
||||
state0 ~= a
|
||||
state1 ~= b
|
||||
state2 ~= c
|
||||
state3 ~= d
|
||||
state4 ~= e
|
||||
state5 ~= f
|
||||
state6 ~= g
|
||||
state7 ~= h
|
||||
state0 ~= a
|
||||
state1 ~= b
|
||||
state2 ~= c
|
||||
state3 ~= d
|
||||
state4 ~= e
|
||||
state5 ~= f
|
||||
state6 ~= g
|
||||
state7 ~= h
|
||||
|
||||
buf = buf[64:]
|
||||
}
|
||||
buf = buf[BLOCK_SIZE:]
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1,517 +0,0 @@
|
||||
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[:])
|
||||
}
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
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]
|
||||
}
|
||||
}
|
||||
@@ -1,806 +0,0 @@
|
||||
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]}
|
||||
}
|
||||
@@ -6,8 +6,10 @@ import "core:mem"
|
||||
SCALAR_SIZE :: 32
|
||||
POINT_SIZE :: 32
|
||||
|
||||
@(private)
|
||||
_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}
|
||||
|
||||
@(private)
|
||||
_scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 {
|
||||
if i < 0 {
|
||||
return 0
|
||||
@@ -15,6 +17,7 @@ _scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 {
|
||||
return (s[i>>3] >> uint(i&7)) & 1
|
||||
}
|
||||
|
||||
@(private)
|
||||
_scalarmult :: proc (out, scalar, point: ^[32]byte) {
|
||||
// Montgomery pseduo-multiplication taken from Monocypher.
|
||||
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
package debug_pe
|
||||
|
||||
PE_SIGNATURE_OFFSET_INDEX_POS :: 0x3c
|
||||
PE_SIGNATURE :: u32le(0x0000_4550) // "PE\x00\x00"
|
||||
PE_SIGNATURE_STRING :: "PE\x00\x00"
|
||||
|
||||
OPTIONAL_HEADER_MAGIC :: enum u16le {
|
||||
PE32 = 0x010b,
|
||||
PE32_PLUS = 0x020b,
|
||||
}
|
||||
|
||||
Optional_Header_Base :: struct #packed {
|
||||
magic: OPTIONAL_HEADER_MAGIC,
|
||||
major_linker_version: u8,
|
||||
minor_linker_version: u8,
|
||||
size_of_code: u32le,
|
||||
size_of_initialized_data: u32le,
|
||||
size_of_uninitialized_data: u32le,
|
||||
address_of_entry_point: u32le,
|
||||
base_of_code: u32le,
|
||||
}
|
||||
|
||||
File_Header :: struct #packed {
|
||||
machine: IMAGE_FILE_MACHINE,
|
||||
number_of_sections: u16le,
|
||||
time_date_stamp: u32le,
|
||||
pointer_to_symbol_table: u32le,
|
||||
number_of_symbols: u32le,
|
||||
size_of_optional_header: u16le,
|
||||
characteristics: IMAGE_FILE_CHARACTERISTICS,
|
||||
}
|
||||
|
||||
Data_Directory :: struct #packed {
|
||||
virtual_address: u32le,
|
||||
size: u32le,
|
||||
}
|
||||
|
||||
Optional_Header32 :: struct #packed {
|
||||
using base: Optional_Header_Base,
|
||||
base_of_data: u32le,
|
||||
image_base: u32le,
|
||||
section_alignment: u32le,
|
||||
file_alignment: u32le,
|
||||
major_operating_system_version: u16le,
|
||||
minor_operating_system_version: u16le,
|
||||
major_image_version: u16le,
|
||||
minor_image_version: u16le,
|
||||
major_subsystem_version: u16le,
|
||||
minor_subsystem_version: u16le,
|
||||
win32_version_value: u32le,
|
||||
size_of_image: u32le,
|
||||
size_of_headers: u32le,
|
||||
check_sum: u32le,
|
||||
subsystem: IMAGE_SUBSYSTEM,
|
||||
dll_characteristics: IMAGE_DLLCHARACTERISTICS,
|
||||
size_of_stack_reserve: u32le,
|
||||
size_of_stack_commit: u32le,
|
||||
size_of_heap_reserve: u32le,
|
||||
size_of_heap_commit: u32le,
|
||||
loader_flags: u32le,
|
||||
number_of_rva_and_sizes: u32le,
|
||||
data_directory: [16]Data_Directory,
|
||||
}
|
||||
|
||||
Optional_Header64 :: struct #packed {
|
||||
using base: Optional_Header_Base,
|
||||
image_base: u64le,
|
||||
section_alignment: u32le,
|
||||
file_alignment: u32le,
|
||||
major_operating_system_version: u16le,
|
||||
minor_operating_system_version: u16le,
|
||||
major_image_version: u16le,
|
||||
minor_image_version: u16le,
|
||||
major_subsystem_version: u16le,
|
||||
minor_subsystem_version: u16le,
|
||||
win32_version_value: u32le,
|
||||
size_of_image: u32le,
|
||||
size_of_headers: u32le,
|
||||
check_sum: u32le,
|
||||
subsystem: IMAGE_SUBSYSTEM,
|
||||
dll_characteristics: IMAGE_DLLCHARACTERISTICS,
|
||||
size_of_stack_reserve: u64le,
|
||||
size_of_stack_commit: u64le,
|
||||
size_of_heap_reserve: u64le,
|
||||
size_of_heap_commit: u64le,
|
||||
loader_flags: u32le,
|
||||
number_of_rva_and_sizes: u32le,
|
||||
data_directory: [16]Data_Directory,
|
||||
}
|
||||
|
||||
// .debug section
|
||||
Debug_Directory_Entry :: struct {
|
||||
characteristics: u32le,
|
||||
time_date_stamp: u32le,
|
||||
major_version: u16le,
|
||||
minor_version: u16le,
|
||||
type: IMAGE_DEBUG_TYPE,
|
||||
size_of_data: u32le,
|
||||
address_of_raw_data: u32le,
|
||||
pointer_to_raw_data: u32le,
|
||||
}
|
||||
|
||||
|
||||
IMAGE_FILE_MACHINE :: enum u16le {
|
||||
UNKNOWN = 0x0,
|
||||
AM33 = 0x1d3,
|
||||
AMD64 = 0x8664,
|
||||
ARM = 0x1c0,
|
||||
ARMNT = 0x1c4,
|
||||
ARM64 = 0xaa64,
|
||||
EBC = 0xebc,
|
||||
I386 = 0x14c,
|
||||
IA64 = 0x200,
|
||||
LOONGARCH32 = 0x6232,
|
||||
LOONGARCH64 = 0x6264,
|
||||
M32R = 0x9041,
|
||||
MIPS16 = 0x266,
|
||||
MIPSFPU = 0x366,
|
||||
MIPSFPU16 = 0x466,
|
||||
POWERPC = 0x1f0,
|
||||
POWERPCFP = 0x1f1,
|
||||
R4000 = 0x166,
|
||||
SH3 = 0x1a2,
|
||||
SH3DSP = 0x1a3,
|
||||
SH4 = 0x1a6,
|
||||
SH5 = 0x1a8,
|
||||
THUMB = 0x1c2,
|
||||
WCEMIPSV2 = 0x169,
|
||||
}
|
||||
|
||||
// IMAGE_DIRECTORY_ENTRY constants
|
||||
IMAGE_DIRECTORY_ENTRY :: enum u8 {
|
||||
EXPORT = 0,
|
||||
IMPORT = 1,
|
||||
RESOURCE = 2,
|
||||
EXCEPTION = 3,
|
||||
SECURITY = 4,
|
||||
BASERELOC = 5,
|
||||
DEBUG = 6,
|
||||
ARCHITECTURE = 7, // reserved
|
||||
GLOBALPTR = 8,
|
||||
TLS = 9,
|
||||
LOAD_CONFIG = 10,
|
||||
BOUND_IMPORT = 11,
|
||||
IAT = 12,
|
||||
DELAY_IMPORT = 13,
|
||||
COM_DESCRIPTOR = 14, // DLR Runtime headers
|
||||
_RESERVED = 15,
|
||||
}
|
||||
#assert(len(IMAGE_DIRECTORY_ENTRY) == 16)
|
||||
|
||||
|
||||
IMAGE_FILE_CHARACTERISTICS :: distinct bit_set[IMAGE_FILE_CHARACTERISTIC; u16le]
|
||||
IMAGE_FILE_CHARACTERISTIC :: enum u16le {
|
||||
RELOCS_STRIPPED = 0,
|
||||
EXECUTABLE_IMAGE = 1,
|
||||
LINE_NUMS_STRIPPED = 2,
|
||||
LOCAL_SYMS_STRIPPED = 3,
|
||||
AGGRESIVE_WS_TRIM = 4,
|
||||
LARGE_ADDRESS_AWARE = 5,
|
||||
|
||||
BYTES_REVERSED_LO = 7,
|
||||
MACHINE_32BIT = 8, // IMAGE_FILE_32BIT_MACHINE originally
|
||||
DEBUG_STRIPPED = 9,
|
||||
REMOVABLE_RUN_FROM_SWAP = 10,
|
||||
NET_RUN_FROM_SWAP = 11,
|
||||
SYSTEM = 12,
|
||||
DLL = 13,
|
||||
UP_SYSTEM_ONLY = 14,
|
||||
BYTES_REVERSED_HI = 15,
|
||||
}
|
||||
|
||||
IMAGE_SUBSYSTEM :: enum u16le {
|
||||
UNKNOWN = 0,
|
||||
NATIVE = 1,
|
||||
WINDOWS_GUI = 2,
|
||||
WINDOWS_CUI = 3,
|
||||
OS2_CUI = 5,
|
||||
POSIX_CUI = 7,
|
||||
NATIVE_WINDOWS = 8,
|
||||
WINDOWS_CE_GUI = 9,
|
||||
EFI_APPLICATION = 10,
|
||||
EFI_BOOT_SERVICE_DRIVER = 11,
|
||||
EFI_RUNTIME_DRIVER = 12,
|
||||
EFI_ROM = 13,
|
||||
XBOX = 14,
|
||||
WINDOWS_BOOT_APPLICATION = 16,
|
||||
}
|
||||
|
||||
IMAGE_DLLCHARACTERISTICS :: distinct bit_set[IMAGE_DLLCHARACTERISTIC; u16le]
|
||||
IMAGE_DLLCHARACTERISTIC :: enum u16le {
|
||||
HIGH_ENTROPY_VA = 5,
|
||||
DYNAMIC_BASE = 6,
|
||||
FORCE_INTEGRITY = 7,
|
||||
NX_COMPAT = 8,
|
||||
NO_ISOLATION = 9,
|
||||
NO_SEH = 10,
|
||||
NO_BIND = 11,
|
||||
APPCONTAINER = 12,
|
||||
WDM_DRIVER = 13,
|
||||
GUARD_CF = 14,
|
||||
TERMINAL_SERVER_AWARE = 15,
|
||||
}
|
||||
|
||||
IMAGE_DEBUG_TYPE :: enum u32le {
|
||||
UNKNOWN = 0, // An unknown value that is ignored by all tools.
|
||||
COFF = 1, // The COFF debug information (line numbers, symbol table, and string table). This type of debug information is also pointed to by fields in the file headers.
|
||||
CODEVIEW = 2, // The Visual C++ debug information.
|
||||
FPO = 3, // The frame pointer omission (FPO) information. This information tells the debugger how to interpret nonstandard stack frames, which use the EBP register for a purpose other than as a frame pointer.
|
||||
MISC = 4, // The location of DBG file.
|
||||
EXCEPTION = 5, // A copy of .pdata section.
|
||||
FIXUP = 6, // Reserved.
|
||||
OMAP_TO_SRC = 7, // The mapping from an RVA in image to an RVA in source image.
|
||||
OMAP_FROM_SRC = 8, // The mapping from an RVA in source image to an RVA in image.
|
||||
BORLAND = 9, // Reserved for Borland.
|
||||
RESERVED10 = 10, // Reserved.
|
||||
CLSID = 11, // Reserved.
|
||||
REPRO = 16, // PE determinism or reproducibility.
|
||||
EX_DLLCHARACTERISTICS = 20, // Extended DLL characteristics bits.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package debug_pe
|
||||
|
||||
Section_Header32 :: struct {
|
||||
name: [8]u8,
|
||||
virtual_size: u32le,
|
||||
virtual_address: u32le,
|
||||
size_of_raw_data: u32le,
|
||||
pointer_to_raw_data: u32le,
|
||||
pointer_to_relocations: u32le,
|
||||
pointer_to_line_numbers: u32le,
|
||||
number_of_relocations: u16le,
|
||||
number_of_line_numbers: u16le,
|
||||
characteristics: IMAGE_SCN_CHARACTERISTICS,
|
||||
}
|
||||
|
||||
Reloc :: struct {
|
||||
virtual_address: u32le,
|
||||
symbol_table_index: u32le,
|
||||
type: IMAGE_REL,
|
||||
}
|
||||
|
||||
IMAGE_SCN_CHARACTERISTICS :: enum u32le {
|
||||
TYPE_NO_PAD = 0x00000008, // The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. = 0x00000010, // Reserved for future use.
|
||||
CNT_CODE = 0x00000020, // The section contains executable code.
|
||||
CNT_INITIALIZED_DATA = 0x00000040, // The section contains initialized data.
|
||||
CNT_UNINITIALIZED_DATA = 0x00000080, // The section contains uninitialized data.
|
||||
LNK_OTHER = 0x00000100, // Reserved for future use.
|
||||
LNK_INFO = 0x00000200, // The section contains comments or other information. The .drectve section has this type. This is valid for object files only. = 0x00000400, // Reserved for future use.
|
||||
LNK_REMOVE = 0x00000800, // The section will not become part of the image. This is valid only for object files.
|
||||
LNK_COMDAT = 0x00001000, // The section contains COMDAT data. For more information, see COMDAT Sections (Object Only). This is valid only for object files.
|
||||
GPREL = 0x00008000, // The section contains data referenced through the global pointer (GP).
|
||||
MEM_PURGEABLE = 0x00020000, // Reserved for future use.
|
||||
MEM_16BIT = 0x00020000, // Reserved for future use.
|
||||
MEM_LOCKED = 0x00040000, // Reserved for future use.
|
||||
MEM_PRELOAD = 0x00080000, // Reserved for future use.
|
||||
ALIGN_1BYTES = 0x00100000, // Align data on a 1-byte boundary. Valid only for object files.
|
||||
ALIGN_2BYTES = 0x00200000, // Align data on a 2-byte boundary. Valid only for object files.
|
||||
ALIGN_4BYTES = 0x00300000, // Align data on a 4-byte boundary. Valid only for object files.
|
||||
ALIGN_8BYTES = 0x00400000, // Align data on an 8-byte boundary. Valid only for object files.
|
||||
ALIGN_16BYTES = 0x00500000, // Align data on a 16-byte boundary. Valid only for object files.
|
||||
ALIGN_32BYTES = 0x00600000, // Align data on a 32-byte boundary. Valid only for object files.
|
||||
ALIGN_64BYTES = 0x00700000, // Align data on a 64-byte boundary. Valid only for object files.
|
||||
ALIGN_128BYTES = 0x00800000, // Align data on a 128-byte boundary. Valid only for object files.
|
||||
ALIGN_256BYTES = 0x00900000, // Align data on a 256-byte boundary. Valid only for object files.
|
||||
ALIGN_512BYTES = 0x00A00000, // Align data on a 512-byte boundary. Valid only for object files.
|
||||
ALIGN_1024BYTES = 0x00B00000, // Align data on a 1024-byte boundary. Valid only for object files.
|
||||
ALIGN_2048BYTES = 0x00C00000, // Align data on a 2048-byte boundary. Valid only for object files.
|
||||
ALIGN_4096BYTES = 0x00D00000, // Align data on a 4096-byte boundary. Valid only for object files.
|
||||
ALIGN_8192BYTES = 0x00E00000, // Align data on an 8192-byte boundary. Valid only for object files.
|
||||
LNK_NRELOC_OVFL = 0x01000000, // The section contains extended relocations.
|
||||
MEM_DISCARDABLE = 0x02000000, // The section can be discarded as needed.
|
||||
MEM_NOT_CACHED = 0x04000000, // The section cannot be cached.
|
||||
MEM_NOT_PAGED = 0x08000000, // The section is not pageable.
|
||||
MEM_SHARED = 0x10000000, // The section can be shared in memory.
|
||||
MEM_EXECUTE = 0x20000000, // The section can be executed as code.
|
||||
MEM_READ = 0x40000000, // The section can be read.
|
||||
MEM_WRITE = 0x80000000, // The section can be written to.
|
||||
}
|
||||
|
||||
|
||||
IMAGE_REL :: enum u16le {
|
||||
I386_ABSOLUTE = 0x0000,
|
||||
I386_DIR16 = 0x0001,
|
||||
I386_REL16 = 0x0002,
|
||||
I386_DIR32 = 0x0006,
|
||||
I386_DIR32NB = 0x0007,
|
||||
I386_SEG12 = 0x0009,
|
||||
I386_SECTION = 0x000A,
|
||||
I386_SECREL = 0x000B,
|
||||
I386_TOKEN = 0x000C,
|
||||
I386_SECREL7 = 0x000D,
|
||||
I386_REL32 = 0x0014,
|
||||
|
||||
AMD64_ABSOLUTE = 0x0000,
|
||||
AMD64_ADDR64 = 0x0001,
|
||||
AMD64_ADDR32 = 0x0002,
|
||||
AMD64_ADDR32NB = 0x0003,
|
||||
AMD64_REL32 = 0x0004,
|
||||
AMD64_REL32_1 = 0x0005,
|
||||
AMD64_REL32_2 = 0x0006,
|
||||
AMD64_REL32_3 = 0x0007,
|
||||
AMD64_REL32_4 = 0x0008,
|
||||
AMD64_REL32_5 = 0x0009,
|
||||
AMD64_SECTION = 0x000A,
|
||||
AMD64_SECREL = 0x000B,
|
||||
AMD64_SECREL7 = 0x000C,
|
||||
AMD64_TOKEN = 0x000D,
|
||||
AMD64_SREL32 = 0x000E,
|
||||
AMD64_PAIR = 0x000F,
|
||||
AMD64_SSPAN32 = 0x0010,
|
||||
|
||||
ARM_ABSOLUTE = 0x0000,
|
||||
ARM_ADDR32 = 0x0001,
|
||||
ARM_ADDR32NB = 0x0002,
|
||||
ARM_BRANCH24 = 0x0003,
|
||||
ARM_BRANCH11 = 0x0004,
|
||||
ARM_SECTION = 0x000E,
|
||||
ARM_SECREL = 0x000F,
|
||||
ARM_MOV32 = 0x0010,
|
||||
|
||||
THUMB_MOV32 = 0x0011,
|
||||
THUMB_BRANCH20 = 0x0012,
|
||||
THUMB_BRANCH24 = 0x0014,
|
||||
THUMB_BLX23 = 0x0015,
|
||||
|
||||
ARM_PAIR = 0x0016,
|
||||
|
||||
ARM64_ABSOLUTE = 0x0000,
|
||||
ARM64_ADDR32 = 0x0001,
|
||||
ARM64_ADDR32NB = 0x0002,
|
||||
ARM64_BRANCH26 = 0x0003,
|
||||
ARM64_PAGEBASE_REL21 = 0x0004,
|
||||
ARM64_REL21 = 0x0005,
|
||||
ARM64_PAGEOFFSET_12A = 0x0006,
|
||||
ARM64_PAGEOFFSET_12L = 0x0007,
|
||||
ARM64_SECREL = 0x0008,
|
||||
ARM64_SECREL_LOW12A = 0x0009,
|
||||
ARM64_SECREL_HIGH12A = 0x000A,
|
||||
ARM64_SECREL_LOW12L = 0x000B,
|
||||
ARM64_TOKEN = 0x000C,
|
||||
ARM64_SECTION = 0x000D,
|
||||
ARM64_ADDR64 = 0x000E,
|
||||
ARM64_BRANCH19 = 0x000F,
|
||||
ARM64_BRANCH14 = 0x0010,
|
||||
ARM64_REL32 = 0x0011,
|
||||
}
|
||||
|
||||
PE_CODE_VIEW_SIGNATURE_RSDS :: u32le(0x5344_5352)
|
||||
@@ -0,0 +1,108 @@
|
||||
package debug_pe
|
||||
|
||||
COFF_SYMBOL_SIZE :: 18
|
||||
|
||||
COFF_Symbol :: struct {
|
||||
name: [8]u8,
|
||||
value: u32le,
|
||||
section_number: i16le,
|
||||
type: IMAGE_SYM_TYPE,
|
||||
storage_class: IMAGE_SYM_CLASS,
|
||||
number_of_aux_symbols: u8,
|
||||
}
|
||||
|
||||
// COFF_Symbol_Aux_Format5 describes the expected form of an aux symbol
|
||||
// attached to a section definition symbol. The PE format defines a
|
||||
// number of different aux symbol formats: format 1 for function
|
||||
// definitions, format 2 for .be and .ef symbols, and so on. Format 5
|
||||
// holds extra info associated with a section definition, including
|
||||
// number of relocations + line numbers, as well as COMDAT info. See
|
||||
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
|
||||
// for more on what's going on here.
|
||||
COFF_Symbol_Aux_Format5 :: struct {
|
||||
size: u32le,
|
||||
num_relocs: u16le,
|
||||
num_line_numbers: u16le,
|
||||
checksum: u32le,
|
||||
sec_num: u16le,
|
||||
selection: IMAGE_COMDAT_SELECT,
|
||||
_: [3]u8, // padding
|
||||
}
|
||||
|
||||
IMAGE_COMDAT_SELECT :: enum u8 {
|
||||
NODUPLICATES = 1,
|
||||
ANY = 2,
|
||||
SAME_SIZE = 3,
|
||||
EXACT_MATCH = 4,
|
||||
ASSOCIATIVE = 5,
|
||||
LARGEST = 6,
|
||||
}
|
||||
|
||||
|
||||
// The symbol record is not yet assigned a section. A value of zero indicates
|
||||
// that a reference to an external symbol is defined elsewhere. A value of
|
||||
// non-zero is a common symbol with a size that is specified by the value.
|
||||
IMAGE_SYM_UNDEFINED :: 0
|
||||
// The symbol has an absolute (non-relocatable) value and is not an address.
|
||||
IMAGE_SYM_ABSOLUTE :: -1
|
||||
// The symbol provides general type or debugging information but does not
|
||||
// correspond to a section. Microsoft tools use this setting along
|
||||
// with .file records (storage class FILE).
|
||||
IMAGE_SYM_DEBUG :: -2
|
||||
|
||||
IMAGE_SYM_TYPE :: enum u16le {
|
||||
NULL = 0,
|
||||
VOID = 1,
|
||||
CHAR = 2,
|
||||
SHORT = 3,
|
||||
INT = 4,
|
||||
LONG = 5,
|
||||
FLOAT = 6,
|
||||
DOUBLE = 7,
|
||||
STRUCT = 8,
|
||||
UNION = 9,
|
||||
ENUM = 10,
|
||||
MOE = 11,
|
||||
BYTE = 12,
|
||||
WORD = 13,
|
||||
UINT = 14,
|
||||
DWORD = 15,
|
||||
PCODE = 32768,
|
||||
|
||||
DTYPE_NULL = 0,
|
||||
DTYPE_POINTER = 0x10,
|
||||
DTYPE_FUNCTION = 0x20,
|
||||
DTYPE_ARRAY = 0x30,
|
||||
}
|
||||
|
||||
IMAGE_SYM_CLASS :: enum u8 {
|
||||
NULL = 0,
|
||||
AUTOMATIC = 1,
|
||||
EXTERNAL = 2,
|
||||
STATIC = 3,
|
||||
REGISTER = 4,
|
||||
EXTERNAL_DEF = 5,
|
||||
LABEL = 6,
|
||||
UNDEFINED_LABEL = 7,
|
||||
MEMBER_OF_STRUCT = 8,
|
||||
ARGUMENT = 9,
|
||||
STRUCT_TAG = 10,
|
||||
MEMBER_OF_UNION = 11,
|
||||
UNION_TAG = 12,
|
||||
TYPE_DEFINITION = 13,
|
||||
UNDEFINED_STATIC = 14,
|
||||
ENUM_TAG = 15,
|
||||
MEMBER_OF_ENUM = 16,
|
||||
REGISTER_PARAM = 17,
|
||||
BIT_FIELD = 18,
|
||||
FAR_EXTERNAL = 68, // Not in PECOFF v8 spec
|
||||
BLOCK = 100,
|
||||
FUNCTION = 101,
|
||||
END_OF_STRUCT = 102,
|
||||
FILE = 103,
|
||||
SECTION = 104,
|
||||
WEAK_EXTERNAL = 105,
|
||||
CLR_TOKEN = 107,
|
||||
|
||||
END_OF_FUNCTION = 255,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
Package core:dynlib implements loading of shared libraries/DLLs and their symbols.
|
||||
|
||||
The behaviour of dynamically loaded libraries is specific to the target platform of the program.
|
||||
For in depth detail on the underlying behaviour please refer to your target platform's documentation.
|
||||
*/
|
||||
package dynlib
|
||||
+81
-2
@@ -1,15 +1,94 @@
|
||||
package dynlib
|
||||
|
||||
/*
|
||||
A handle to a dynamically loaded library.
|
||||
*/
|
||||
Library :: distinct rawptr
|
||||
|
||||
load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||
/*
|
||||
Loads a dynamic library from the filesystem. The paramater `global_symbols` makes the symbols in the loaded
|
||||
library available to resolve references in subsequently loaded libraries.
|
||||
|
||||
The paramater `global_symbols` is only used for the platforms `linux`, `darwin`, `freebsd` and `openbsd`.
|
||||
On `windows` this paramater is ignored.
|
||||
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlopen`.
|
||||
On `windows` refer to `LoadLibraryW`.
|
||||
|
||||
**Implicit Allocators**
|
||||
`context.temp_allocator`
|
||||
|
||||
Example:
|
||||
import "core:dynlib"
|
||||
import "core:fmt"
|
||||
|
||||
load_my_library :: proc() {
|
||||
LIBRARY_PATH :: "my_library.dll"
|
||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||
if ! ok {
|
||||
return
|
||||
}
|
||||
fmt.println("The library %q was successfully loaded", LIBRARY_PATH)
|
||||
}
|
||||
*/
|
||||
load_library :: proc(path: string, global_symbols := false) -> (library: Library, did_load: bool) {
|
||||
return _load_library(path, global_symbols)
|
||||
}
|
||||
|
||||
unload_library :: proc(library: Library) -> bool {
|
||||
/*
|
||||
Unloads a dynamic library.
|
||||
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlclose`.
|
||||
On `windows` refer to `FreeLibrary`.
|
||||
|
||||
Example:
|
||||
import "core:dynlib"
|
||||
import "core:fmt"
|
||||
|
||||
load_then_unload_my_library :: proc() {
|
||||
LIBRARY_PATH :: "my_library.dll"
|
||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||
if ! ok {
|
||||
return
|
||||
}
|
||||
did_unload := dynlib.unload_library(library)
|
||||
if ! did_unload {
|
||||
return
|
||||
}
|
||||
fmt.println("The library %q was successfully unloaded", LIBRARY_PATH)
|
||||
}
|
||||
*/
|
||||
unload_library :: proc(library: Library) -> (did_unload: bool) {
|
||||
return _unload_library(library)
|
||||
}
|
||||
|
||||
/*
|
||||
Loads the address of a procedure/variable from a dynamic library.
|
||||
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlsym`.
|
||||
On `windows` refer to `GetProcAddress`.
|
||||
|
||||
**Implicit Allocators**
|
||||
`context.temp_allocator`
|
||||
|
||||
Example:
|
||||
import "core:dynlib"
|
||||
import "core:fmt"
|
||||
|
||||
find_a_in_my_library :: proc() {
|
||||
LIBRARY_PATH :: "my_library.dll"
|
||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||
if ! ok {
|
||||
return
|
||||
}
|
||||
|
||||
a, found_a := dynlib.symbol_address(library, "a")
|
||||
if found_a do fmt.printf("The symbol %q was found at the address %v", "a", a)
|
||||
}
|
||||
*/
|
||||
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) #optional_ok {
|
||||
return _symbol_address(library, symbol)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//+build js
|
||||
//+private
|
||||
package dynlib
|
||||
|
||||
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
_unload_library :: proc(library: Library) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||
return nil, false
|
||||
}
|
||||
@@ -4,10 +4,12 @@ package dynlib
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:strings"
|
||||
import "core:runtime"
|
||||
|
||||
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wide_path := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
handle := cast(Library)win32.LoadLibraryW(wide_path)
|
||||
return handle, handle != nil
|
||||
@@ -19,6 +21,7 @@ _unload_library :: proc(library: Library) -> bool {
|
||||
}
|
||||
|
||||
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
c_str := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
|
||||
found = ptr != nil
|
||||
|
||||
@@ -248,7 +248,7 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all
|
||||
field_length += 1
|
||||
|
||||
case '\n', '\r':
|
||||
if !is_quoted { break read_loop }
|
||||
is_quoted or_break read_loop
|
||||
|
||||
case r.comma:
|
||||
field_length = 0
|
||||
|
||||
@@ -42,7 +42,7 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
|
||||
}
|
||||
}
|
||||
case:
|
||||
if strings.contains_rune(field, w.comma) >= 0 {
|
||||
if strings.contains_rune(field, w.comma) {
|
||||
return true
|
||||
}
|
||||
if strings.contains_any(field, CHAR_SET) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user