tiger.odin 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package tiger
  2. /*
  3. Copyright 2021 zhibog
  4. Made available under the BSD-3 license.
  5. List of contributors:
  6. zhibog, dotbmp: Initial implementation.
  7. Interface for the Tiger1 variant of the Tiger hashing algorithm as defined in <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
  8. */
  9. import "core:os"
  10. import "core:io"
  11. import "../_tiger"
  12. /*
  13. High level API
  14. */
  15. DIGEST_SIZE_128 :: 16
  16. DIGEST_SIZE_160 :: 20
  17. DIGEST_SIZE_192 :: 24
  18. // hash_string_128 will hash the given input and return the
  19. // computed hash
  20. hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte {
  21. return hash_bytes_128(transmute([]byte)(data))
  22. }
  23. // hash_bytes_128 will hash the given input and return the
  24. // computed hash
  25. hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
  26. hash: [DIGEST_SIZE_128]byte
  27. ctx: _tiger.Tiger_Context
  28. ctx.ver = 1
  29. _tiger.init(&ctx)
  30. _tiger.update(&ctx, data)
  31. _tiger.final(&ctx, hash[:])
  32. return hash
  33. }
  34. // hash_string_to_buffer_128 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_128 :: proc(data: string, hash: []byte) {
  38. hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
  39. }
  40. // hash_bytes_to_buffer_128 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_128 :: proc(data, hash: []byte) {
  44. assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size")
  45. ctx: _tiger.Tiger_Context
  46. ctx.ver = 1
  47. _tiger.init(&ctx)
  48. _tiger.update(&ctx, data)
  49. _tiger.final(&ctx, hash)
  50. }
  51. // hash_stream_128 will read the stream in chunks and compute a
  52. // hash from its contents
  53. hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) {
  54. hash: [DIGEST_SIZE_128]byte
  55. ctx: _tiger.Tiger_Context
  56. ctx.ver = 1
  57. _tiger.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. _tiger.update(&ctx, buf[:read])
  65. }
  66. }
  67. _tiger.final(&ctx, hash[:])
  68. return hash, true
  69. }
  70. // hash_file_128 will read the file provided by the given handle
  71. // and compute a hash
  72. hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) {
  73. if !load_at_once {
  74. return hash_stream_128(os.stream_from_handle(hd))
  75. } else {
  76. if buf, ok := os.read_entire_file(hd); ok {
  77. return hash_bytes_128(buf[:]), ok
  78. }
  79. }
  80. return [DIGEST_SIZE_128]byte{}, false
  81. }
  82. hash_128 :: proc {
  83. hash_stream_128,
  84. hash_file_128,
  85. hash_bytes_128,
  86. hash_string_128,
  87. hash_bytes_to_buffer_128,
  88. hash_string_to_buffer_128,
  89. }
  90. // hash_string_160 will hash the given input and return the
  91. // computed hash
  92. hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte {
  93. return hash_bytes_160(transmute([]byte)(data))
  94. }
  95. // hash_bytes_160 will hash the given input and return the
  96. // computed hash
  97. hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
  98. hash: [DIGEST_SIZE_160]byte
  99. ctx: _tiger.Tiger_Context
  100. ctx.ver = 1
  101. _tiger.init(&ctx)
  102. _tiger.update(&ctx, data)
  103. _tiger.final(&ctx, hash[:])
  104. return hash
  105. }
  106. // hash_string_to_buffer_160 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_160 :: proc(data: string, hash: []byte) {
  110. hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
  111. }
  112. // hash_bytes_to_buffer_160 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_160 :: proc(data, hash: []byte) {
  116. assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size")
  117. ctx: _tiger.Tiger_Context
  118. ctx.ver = 1
  119. _tiger.init(&ctx)
  120. _tiger.update(&ctx, data)
  121. _tiger.final(&ctx, hash)
  122. }
  123. // hash_stream_160 will read the stream in chunks and compute a
  124. // hash from its contents
  125. hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) {
  126. hash: [DIGEST_SIZE_160]byte
  127. ctx: _tiger.Tiger_Context
  128. ctx.ver = 1
  129. _tiger.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. _tiger.update(&ctx, buf[:read])
  137. }
  138. }
  139. _tiger.final(&ctx, hash[:])
  140. return hash, true
  141. }
  142. // hash_file_160 will read the file provided by the given handle
  143. // and compute a hash
  144. hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) {
  145. if !load_at_once {
  146. return hash_stream_160(os.stream_from_handle(hd))
  147. } else {
  148. if buf, ok := os.read_entire_file(hd); ok {
  149. return hash_bytes_160(buf[:]), ok
  150. }
  151. }
  152. return [DIGEST_SIZE_160]byte{}, false
  153. }
  154. hash_160 :: proc {
  155. hash_stream_160,
  156. hash_file_160,
  157. hash_bytes_160,
  158. hash_string_160,
  159. hash_bytes_to_buffer_160,
  160. hash_string_to_buffer_160,
  161. }
  162. // hash_string_192 will hash the given input and return the
  163. // computed hash
  164. hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte {
  165. return hash_bytes_192(transmute([]byte)(data))
  166. }
  167. // hash_bytes_192 will hash the given input and return the
  168. // computed hash
  169. hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
  170. hash: [DIGEST_SIZE_192]byte
  171. ctx: _tiger.Tiger_Context
  172. ctx.ver = 1
  173. _tiger.init(&ctx)
  174. _tiger.update(&ctx, data)
  175. _tiger.final(&ctx, hash[:])
  176. return hash
  177. }
  178. // hash_string_to_buffer_192 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_192 :: proc(data: string, hash: []byte) {
  182. hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
  183. }
  184. // hash_bytes_to_buffer_192 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_192 :: proc(data, hash: []byte) {
  188. assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size")
  189. ctx: _tiger.Tiger_Context
  190. ctx.ver = 1
  191. _tiger.init(&ctx)
  192. _tiger.update(&ctx, data)
  193. _tiger.final(&ctx, hash)
  194. }
  195. // hash_stream_192 will read the stream in chunks and compute a
  196. // hash from its contents
  197. hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) {
  198. hash: [DIGEST_SIZE_192]byte
  199. ctx: _tiger.Tiger_Context
  200. ctx.ver = 1
  201. _tiger.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. _tiger.update(&ctx, buf[:read])
  209. }
  210. }
  211. _tiger.final(&ctx, hash[:])
  212. return hash, true
  213. }
  214. // hash_file_192 will read the file provided by the given handle
  215. // and compute a hash
  216. hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) {
  217. if !load_at_once {
  218. return hash_stream_192(os.stream_from_handle(hd))
  219. } else {
  220. if buf, ok := os.read_entire_file(hd); ok {
  221. return hash_bytes_192(buf[:]), ok
  222. }
  223. }
  224. return [DIGEST_SIZE_192]byte{}, false
  225. }
  226. hash_192 :: proc {
  227. hash_stream_192,
  228. hash_file_192,
  229. hash_bytes_192,
  230. hash_string_192,
  231. hash_bytes_to_buffer_192,
  232. hash_string_to_buffer_192,
  233. }
  234. /*
  235. Low level API
  236. */
  237. Tiger_Context :: _tiger.Tiger_Context
  238. init :: proc(ctx: ^_tiger.Tiger_Context) {
  239. ctx.ver = 1
  240. _tiger.init(ctx)
  241. }
  242. update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) {
  243. _tiger.update(ctx, data)
  244. }
  245. final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) {
  246. _tiger.final(ctx, hash)
  247. }