groestl.odin 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. package groestl
  2. /*
  3. Copyright 2021 zhibog
  4. Made available under the BSD-3 license.
  5. List of contributors:
  6. zhibog, dotbmp: Initial implementation.
  7. Implementation of the GROESTL hashing algorithm, as defined in <http://www.groestl.info/Groestl.zip>
  8. */
  9. import "core:os"
  10. import "core:io"
  11. /*
  12. High level API
  13. */
  14. DIGEST_SIZE_224 :: 28
  15. DIGEST_SIZE_256 :: 32
  16. DIGEST_SIZE_384 :: 48
  17. DIGEST_SIZE_512 :: 64
  18. // hash_string_224 will hash the given input and return the
  19. // computed hash
  20. hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
  21. return hash_bytes_224(transmute([]byte)(data))
  22. }
  23. // hash_bytes_224 will hash the given input and return the
  24. // computed hash
  25. hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
  26. hash: [DIGEST_SIZE_224]byte
  27. ctx: Groestl_Context
  28. ctx.hashbitlen = 224
  29. init(&ctx)
  30. update(&ctx, data)
  31. final(&ctx, hash[:])
  32. return hash
  33. }
  34. // hash_string_to_buffer_224 will hash the given input and assign the
  35. // computed hash to the second parameter.
  36. // It requires that the destination buffer is at least as big as the digest size
  37. hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
  38. hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
  39. }
  40. // hash_bytes_to_buffer_224 will hash the given input and write the
  41. // computed hash into the second parameter.
  42. // It requires that the destination buffer is at least as big as the digest size
  43. hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
  44. assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
  45. ctx: Groestl_Context
  46. ctx.hashbitlen = 224
  47. init(&ctx)
  48. update(&ctx, data)
  49. final(&ctx, hash)
  50. }
  51. // hash_stream_224 will read the stream in chunks and compute a
  52. // hash from its contents
  53. hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
  54. hash: [DIGEST_SIZE_224]byte
  55. ctx: Groestl_Context
  56. ctx.hashbitlen = 224
  57. init(&ctx)
  58. buf := make([]byte, 512)
  59. defer delete(buf)
  60. read := 1
  61. for read > 0 {
  62. read, _ = s->impl_read(buf)
  63. if read > 0 {
  64. update(&ctx, buf[:read])
  65. }
  66. }
  67. final(&ctx, hash[:])
  68. return hash, true
  69. }
  70. // hash_file_224 will read the file provided by the given handle
  71. // and compute a hash
  72. hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
  73. if !load_at_once {
  74. return hash_stream_224(os.stream_from_handle(hd))
  75. } else {
  76. if buf, ok := os.read_entire_file(hd); ok {
  77. return hash_bytes_224(buf[:]), ok
  78. }
  79. }
  80. return [DIGEST_SIZE_224]byte{}, false
  81. }
  82. hash_224 :: proc {
  83. hash_stream_224,
  84. hash_file_224,
  85. hash_bytes_224,
  86. hash_string_224,
  87. hash_bytes_to_buffer_224,
  88. hash_string_to_buffer_224,
  89. }
  90. // hash_string_256 will hash the given input and return the
  91. // computed hash
  92. hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
  93. return hash_bytes_256(transmute([]byte)(data))
  94. }
  95. // hash_bytes_256 will hash the given input and return the
  96. // computed hash
  97. hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
  98. hash: [DIGEST_SIZE_256]byte
  99. ctx: Groestl_Context
  100. ctx.hashbitlen = 256
  101. init(&ctx)
  102. update(&ctx, data)
  103. final(&ctx, hash[:])
  104. return hash
  105. }
  106. // hash_string_to_buffer_256 will hash the given input and assign the
  107. // computed hash to the second parameter.
  108. // It requires that the destination buffer is at least as big as the digest size
  109. hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
  110. hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
  111. }
  112. // hash_bytes_to_buffer_256 will hash the given input and write the
  113. // computed hash into the second parameter.
  114. // It requires that the destination buffer is at least as big as the digest size
  115. hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
  116. assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
  117. ctx: Groestl_Context
  118. ctx.hashbitlen = 256
  119. init(&ctx)
  120. update(&ctx, data)
  121. final(&ctx, hash)
  122. }
  123. // hash_stream_256 will read the stream in chunks and compute a
  124. // hash from its contents
  125. hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
  126. hash: [DIGEST_SIZE_256]byte
  127. ctx: Groestl_Context
  128. ctx.hashbitlen = 256
  129. init(&ctx)
  130. buf := make([]byte, 512)
  131. defer delete(buf)
  132. read := 1
  133. for read > 0 {
  134. read, _ = s->impl_read(buf)
  135. if read > 0 {
  136. update(&ctx, buf[:read])
  137. }
  138. }
  139. final(&ctx, hash[:])
  140. return hash, true
  141. }
  142. // hash_file_256 will read the file provided by the given handle
  143. // and compute a hash
  144. hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
  145. if !load_at_once {
  146. return hash_stream_256(os.stream_from_handle(hd))
  147. } else {
  148. if buf, ok := os.read_entire_file(hd); ok {
  149. return hash_bytes_256(buf[:]), ok
  150. }
  151. }
  152. return [DIGEST_SIZE_256]byte{}, false
  153. }
  154. hash_256 :: proc {
  155. hash_stream_256,
  156. hash_file_256,
  157. hash_bytes_256,
  158. hash_string_256,
  159. hash_bytes_to_buffer_256,
  160. hash_string_to_buffer_256,
  161. }
  162. // hash_string_384 will hash the given input and return the
  163. // computed hash
  164. hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
  165. return hash_bytes_384(transmute([]byte)(data))
  166. }
  167. // hash_bytes_384 will hash the given input and return the
  168. // computed hash
  169. hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
  170. hash: [DIGEST_SIZE_384]byte
  171. ctx: Groestl_Context
  172. ctx.hashbitlen = 384
  173. init(&ctx)
  174. update(&ctx, data)
  175. final(&ctx, hash[:])
  176. return hash
  177. }
  178. // hash_string_to_buffer_384 will hash the given input and assign the
  179. // computed hash to the second parameter.
  180. // It requires that the destination buffer is at least as big as the digest size
  181. hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
  182. hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
  183. }
  184. // hash_bytes_to_buffer_384 will hash the given input and write the
  185. // computed hash into the second parameter.
  186. // It requires that the destination buffer is at least as big as the digest size
  187. hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
  188. assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
  189. ctx: Groestl_Context
  190. ctx.hashbitlen = 384
  191. init(&ctx)
  192. update(&ctx, data)
  193. final(&ctx, hash)
  194. }
  195. // hash_stream_384 will read the stream in chunks and compute a
  196. // hash from its contents
  197. hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
  198. hash: [DIGEST_SIZE_384]byte
  199. ctx: Groestl_Context
  200. ctx.hashbitlen = 384
  201. init(&ctx)
  202. buf := make([]byte, 512)
  203. defer delete(buf)
  204. read := 1
  205. for read > 0 {
  206. read, _ = s->impl_read(buf)
  207. if read > 0 {
  208. update(&ctx, buf[:read])
  209. }
  210. }
  211. final(&ctx, hash[:])
  212. return hash, true
  213. }
  214. // hash_file_384 will read the file provided by the given handle
  215. // and compute a hash
  216. hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
  217. if !load_at_once {
  218. return hash_stream_384(os.stream_from_handle(hd))
  219. } else {
  220. if buf, ok := os.read_entire_file(hd); ok {
  221. return hash_bytes_384(buf[:]), ok
  222. }
  223. }
  224. return [DIGEST_SIZE_384]byte{}, false
  225. }
  226. hash_384 :: proc {
  227. hash_stream_384,
  228. hash_file_384,
  229. hash_bytes_384,
  230. hash_string_384,
  231. hash_bytes_to_buffer_384,
  232. hash_string_to_buffer_384,
  233. }
  234. // hash_string_512 will hash the given input and return the
  235. // computed hash
  236. hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
  237. return hash_bytes_512(transmute([]byte)(data))
  238. }
  239. // hash_bytes_512 will hash the given input and return the
  240. // computed hash
  241. hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
  242. hash: [DIGEST_SIZE_512]byte
  243. ctx: Groestl_Context
  244. ctx.hashbitlen = 512
  245. init(&ctx)
  246. update(&ctx, data)
  247. final(&ctx, hash[:])
  248. return hash
  249. }
  250. // hash_string_to_buffer_512 will hash the given input and assign the
  251. // computed hash to the second parameter.
  252. // It requires that the destination buffer is at least as big as the digest size
  253. hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
  254. hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
  255. }
  256. // hash_bytes_to_buffer_512 will hash the given input and write the
  257. // computed hash into the second parameter.
  258. // It requires that the destination buffer is at least as big as the digest size
  259. hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
  260. assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
  261. ctx: Groestl_Context
  262. ctx.hashbitlen = 512
  263. init(&ctx)
  264. update(&ctx, data)
  265. final(&ctx, hash)
  266. }
  267. // hash_stream_512 will read the stream in chunks and compute a
  268. // hash from its contents
  269. hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
  270. hash: [DIGEST_SIZE_512]byte
  271. ctx: Groestl_Context
  272. ctx.hashbitlen = 512
  273. init(&ctx)
  274. buf := make([]byte, 512)
  275. defer delete(buf)
  276. read := 1
  277. for read > 0 {
  278. read, _ = s->impl_read(buf)
  279. if read > 0 {
  280. update(&ctx, buf[:read])
  281. }
  282. }
  283. final(&ctx, hash[:])
  284. return hash, true
  285. }
  286. // hash_file_512 will read the file provided by the given handle
  287. // and compute a hash
  288. hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
  289. if !load_at_once {
  290. return hash_stream_512(os.stream_from_handle(hd))
  291. } else {
  292. if buf, ok := os.read_entire_file(hd); ok {
  293. return hash_bytes_512(buf[:]), ok
  294. }
  295. }
  296. return [DIGEST_SIZE_512]byte{}, false
  297. }
  298. hash_512 :: proc {
  299. hash_stream_512,
  300. hash_file_512,
  301. hash_bytes_512,
  302. hash_string_512,
  303. hash_bytes_to_buffer_512,
  304. hash_string_to_buffer_512,
  305. }
  306. /*
  307. Low level API
  308. */
  309. init :: proc(ctx: ^Groestl_Context) {
  310. assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
  311. if ctx.hashbitlen <= 256 {
  312. ctx.rounds = 10
  313. ctx.columns = 8
  314. ctx.statesize = 64
  315. } else {
  316. ctx.rounds = 14
  317. ctx.columns = 16
  318. ctx.statesize = 128
  319. }
  320. for i := 8 - size_of(i32); i < 8; i += 1 {
  321. ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i))))
  322. }
  323. }
  324. update :: proc(ctx: ^Groestl_Context, data: []byte) {
  325. databitlen := len(data) * 8
  326. msglen := databitlen / 8
  327. rem := databitlen % 8
  328. i: int
  329. assert(ctx.bits_in_last_byte == 0)
  330. if ctx.buf_ptr != 0 {
  331. for i = 0; ctx.buf_ptr < ctx.statesize && i < msglen; i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 {
  332. ctx.buffer[ctx.buf_ptr] = data[i]
  333. }
  334. if ctx.buf_ptr < ctx.statesize {
  335. if rem != 0 {
  336. ctx.bits_in_last_byte = rem
  337. ctx.buffer[ctx.buf_ptr] = data[i]
  338. ctx.buf_ptr += 1
  339. }
  340. return
  341. }
  342. ctx.buf_ptr = 0
  343. transform(ctx, ctx.buffer[:], u32(ctx.statesize))
  344. }
  345. transform(ctx, data[i:], u32(msglen - i))
  346. i += ((msglen - i) / ctx.statesize) * ctx.statesize
  347. for i < msglen {
  348. ctx.buffer[ctx.buf_ptr] = data[i]
  349. i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1
  350. }
  351. if rem != 0 {
  352. ctx.bits_in_last_byte = rem
  353. ctx.buffer[ctx.buf_ptr] = data[i]
  354. ctx.buf_ptr += 1
  355. }
  356. }
  357. final :: proc(ctx: ^Groestl_Context, hash: []byte) {
  358. hashbytelen := ctx.hashbitlen / 8
  359. if ctx.bits_in_last_byte != 0 {
  360. ctx.buffer[ctx.buf_ptr - 1] &= ((1 << uint(ctx.bits_in_last_byte)) - 1) << (8 - uint(ctx.bits_in_last_byte))
  361. ctx.buffer[ctx.buf_ptr - 1] ~= 0x1 << (7 - uint(ctx.bits_in_last_byte))
  362. } else {
  363. ctx.buffer[ctx.buf_ptr] = 0x80
  364. ctx.buf_ptr += 1
  365. }
  366. if ctx.buf_ptr > ctx.statesize - 8 {
  367. for ctx.buf_ptr < ctx.statesize {
  368. ctx.buffer[ctx.buf_ptr] = 0
  369. ctx.buf_ptr += 1
  370. }
  371. transform(ctx, ctx.buffer[:], u32(ctx.statesize))
  372. ctx.buf_ptr = 0
  373. }
  374. for ctx.buf_ptr < ctx.statesize - 8 {
  375. ctx.buffer[ctx.buf_ptr] = 0
  376. ctx.buf_ptr += 1
  377. }
  378. ctx.block_counter += 1
  379. ctx.buf_ptr = ctx.statesize
  380. for ctx.buf_ptr > ctx.statesize - 8 {
  381. ctx.buf_ptr -= 1
  382. ctx.buffer[ctx.buf_ptr] = byte(ctx.block_counter)
  383. ctx.block_counter >>= 8
  384. }
  385. transform(ctx, ctx.buffer[:], u32(ctx.statesize))
  386. output_transformation(ctx)
  387. for i, j := ctx.statesize - hashbytelen , 0; i < ctx.statesize; i, j = i + 1, j + 1 {
  388. hash[j] = ctx.chaining[i % 8][i / 8]
  389. }
  390. }
  391. /*
  392. GROESTL implementation
  393. */
  394. SBOX := [256]byte {
  395. 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
  396. 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
  397. 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
  398. 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
  399. 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
  400. 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
  401. 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
  402. 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
  403. 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
  404. 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
  405. 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
  406. 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
  407. 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
  408. 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
  409. 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
  410. 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
  411. 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
  412. 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
  413. 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
  414. 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
  415. 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
  416. 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
  417. 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
  418. 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
  419. 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
  420. 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
  421. 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
  422. 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
  423. 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
  424. 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
  425. 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
  426. 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
  427. }
  428. SHIFT := [2][2][8]int {
  429. {{0, 1, 2, 3, 4, 5, 6, 7}, {1, 3, 5, 7, 0, 2, 4, 6}},
  430. {{0, 1, 2, 3, 4, 5, 6, 11}, {1, 3, 5, 11, 0, 2, 4, 6}},
  431. }
  432. Groestl_Context :: struct {
  433. chaining: [8][16]byte,
  434. block_counter: u64,
  435. hashbitlen: int,
  436. buffer: [128]byte,
  437. buf_ptr: int,
  438. bits_in_last_byte: int,
  439. columns: int,
  440. rounds: int,
  441. statesize: int,
  442. }
  443. Groestl_Variant :: enum {
  444. P512 = 0,
  445. Q512 = 1,
  446. P1024 = 2,
  447. Q1024 = 3,
  448. }
  449. MUL2 :: #force_inline proc "contextless"(b: byte) -> byte {
  450. return (b >> 7) != 0 ? (b << 1) ~ 0x1b : (b << 1)
  451. }
  452. MUL3 :: #force_inline proc "contextless"(b: byte) -> byte {
  453. return MUL2(b) ~ b
  454. }
  455. MUL4 :: #force_inline proc "contextless"(b: byte) -> byte {
  456. return MUL2(MUL2(b))
  457. }
  458. MUL5 :: #force_inline proc "contextless"(b: byte) -> byte {
  459. return MUL4(b) ~ b
  460. }
  461. MUL6 :: #force_inline proc "contextless"(b: byte) -> byte {
  462. return MUL4(b) ~ MUL2(b)
  463. }
  464. MUL7 :: #force_inline proc "contextless"(b: byte) -> byte {
  465. return MUL4(b) ~ MUL2(b) ~ b
  466. }
  467. sub_bytes :: #force_inline proc (x: [][16]byte, columns: int) {
  468. for i := 0; i < 8; i += 1 {
  469. for j := 0; j < columns; j += 1 {
  470. x[i][j] = SBOX[x[i][j]]
  471. }
  472. }
  473. }
  474. shift_bytes :: #force_inline proc (x: [][16]byte, columns: int, v: Groestl_Variant) {
  475. temp: [16]byte
  476. R := &SHIFT[int(v) / 2][int(v) & 1]
  477. for i := 0; i < 8; i += 1 {
  478. for j := 0; j < columns; j += 1 {
  479. temp[j] = x[i][(j + R[i]) % columns]
  480. }
  481. for j := 0; j < columns; j += 1 {
  482. x[i][j] = temp[j]
  483. }
  484. }
  485. }
  486. mix_bytes :: #force_inline proc (x: [][16]byte, columns: int) {
  487. temp: [8]byte
  488. for i := 0; i < columns; i += 1 {
  489. for j := 0; j < 8; j += 1 {
  490. temp[j] = MUL2(x[(j + 0) % 8][i]) ~
  491. MUL2(x[(j + 1) % 8][i]) ~
  492. MUL3(x[(j + 2) % 8][i]) ~
  493. MUL4(x[(j + 3) % 8][i]) ~
  494. MUL5(x[(j + 4) % 8][i]) ~
  495. MUL3(x[(j + 5) % 8][i]) ~
  496. MUL5(x[(j + 6) % 8][i]) ~
  497. MUL7(x[(j + 7) % 8][i])
  498. }
  499. for j := 0; j < 8; j += 1 {
  500. x[j][i] = temp[j]
  501. }
  502. }
  503. }
  504. p :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) {
  505. v := ctx.columns == 8 ? Groestl_Variant.P512 : Groestl_Variant.P1024
  506. for i := 0; i < ctx.rounds; i += 1 {
  507. add_roundconstant(x, ctx.columns, byte(i), v)
  508. sub_bytes(x, ctx.columns)
  509. shift_bytes(x, ctx.columns, v)
  510. mix_bytes(x, ctx.columns)
  511. }
  512. }
  513. q :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) {
  514. v := ctx.columns == 8 ? Groestl_Variant.Q512 : Groestl_Variant.Q1024
  515. for i := 0; i < ctx.rounds; i += 1 {
  516. add_roundconstant(x, ctx.columns, byte(i), v)
  517. sub_bytes(x, ctx.columns)
  518. shift_bytes(x, ctx.columns, v)
  519. mix_bytes(x, ctx.columns)
  520. }
  521. }
  522. transform :: proc(ctx: ^Groestl_Context, input: []byte, msglen: u32) {
  523. tmp1, tmp2: [8][16]byte
  524. input, msglen := input, msglen
  525. for msglen >= u32(ctx.statesize) {
  526. for i := 0; i < 8; i += 1 {
  527. for j := 0; j < ctx.columns; j += 1 {
  528. tmp1[i][j] = ctx.chaining[i][j] ~ input[j * 8 + i]
  529. tmp2[i][j] = input[j * 8 + i]
  530. }
  531. }
  532. p(ctx, tmp1[:])
  533. q(ctx, tmp2[:])
  534. for i := 0; i < 8; i += 1 {
  535. for j := 0; j < ctx.columns; j += 1 {
  536. ctx.chaining[i][j] ~= tmp1[i][j] ~ tmp2[i][j]
  537. }
  538. }
  539. ctx.block_counter += 1
  540. msglen -= u32(ctx.statesize)
  541. input = input[ctx.statesize:]
  542. }
  543. }
  544. output_transformation :: proc(ctx: ^Groestl_Context) {
  545. temp: [8][16]byte
  546. for i := 0; i < 8; i += 1 {
  547. for j := 0; j < ctx.columns; j += 1 {
  548. temp[i][j] = ctx.chaining[i][j]
  549. }
  550. }
  551. p(ctx, temp[:])
  552. for i := 0; i < 8; i += 1 {
  553. for j := 0; j < ctx.columns; j += 1 {
  554. ctx.chaining[i][j] ~= temp[i][j]
  555. }
  556. }
  557. }
  558. add_roundconstant :: proc(x: [][16]byte, columns: int, round: byte, v: Groestl_Variant) {
  559. switch (i32(v) & 1) {
  560. case 0:
  561. for i := 0; i < columns; i += 1 {
  562. x[0][i] ~= byte(i << 4) ~ round
  563. }
  564. case 1:
  565. for i := 0; i < columns; i += 1 {
  566. for j := 0; j < 7; j += 1 {
  567. x[j][i] ~= 0xff
  568. }
  569. }
  570. for i := 0; i < columns; i += 1 {
  571. x[7][i] ~= byte(i << 4) ~ 0xff ~ round
  572. }
  573. }
  574. }