blake2s.odin 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package blake2s
  2. /*
  3. Copyright 2021 zhibog
  4. Made available under the BSD-3 license.
  5. List of contributors:
  6. zhibog, dotbmp: Initial implementation.
  7. Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings.
  8. Interface for the BLAKE2S hashing algorithm.
  9. BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
  10. */
  11. import "core:os"
  12. import "core:io"
  13. import "../_ctx"
  14. import "../_blake2"
  15. /*
  16. Context initialization and switching between the Odin implementation and the bindings
  17. */
  18. USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false))
  19. @(private)
  20. _init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context {
  21. ctx := _ctx._init_vtable()
  22. when USE_BOTAN_LIB {
  23. use_botan()
  24. } else {
  25. _assign_hash_vtable(ctx)
  26. }
  27. return ctx
  28. }
  29. @(private)
  30. _assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) {
  31. ctx.hash_bytes_32 = hash_bytes_odin
  32. ctx.hash_file_32 = hash_file_odin
  33. ctx.hash_stream_32 = hash_stream_odin
  34. ctx.init = _init_odin
  35. ctx.update = _update_odin
  36. ctx.final = _final_odin
  37. }
  38. _hash_impl := _init_vtable()
  39. // use_botan does nothing, since Blake2s is not available in Botan
  40. @(warning="Blake2s is not provided by the Botan API. Odin implementation will be used")
  41. use_botan :: #force_inline proc() {
  42. use_odin()
  43. }
  44. // use_odin assigns the internal vtable of the hash context to use the Odin implementation
  45. use_odin :: #force_inline proc() {
  46. _assign_hash_vtable(_hash_impl)
  47. }
  48. /*
  49. High level API
  50. */
  51. // hash_string will hash the given input and return the
  52. // computed hash
  53. hash_string :: proc(data: string) -> [32]byte {
  54. return hash_bytes(transmute([]byte)(data))
  55. }
  56. // hash_bytes will hash the given input and return the
  57. // computed hash
  58. hash_bytes :: proc(data: []byte) -> [32]byte {
  59. _create_blake2s_ctx()
  60. return _hash_impl->hash_bytes_32(data)
  61. }
  62. // hash_stream will read the stream in chunks and compute a
  63. // hash from its contents
  64. hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) {
  65. _create_blake2s_ctx()
  66. return _hash_impl->hash_stream_32(s)
  67. }
  68. // hash_file will read the file provided by the given handle
  69. // and compute a hash
  70. hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
  71. _create_blake2s_ctx()
  72. return _hash_impl->hash_file_32(hd, load_at_once)
  73. }
  74. hash :: proc {
  75. hash_stream,
  76. hash_file,
  77. hash_bytes,
  78. hash_string,
  79. }
  80. /*
  81. Low level API
  82. */
  83. init :: proc(ctx: ^_ctx.Hash_Context) {
  84. _hash_impl->init()
  85. }
  86. update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) {
  87. _hash_impl->update(data)
  88. }
  89. final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
  90. _hash_impl->final(hash)
  91. }
  92. hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte {
  93. hash: [32]byte
  94. if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok {
  95. _blake2.init_odin(&c)
  96. _blake2.update_odin(&c, data)
  97. _blake2.blake2s_final_odin(&c, hash[:])
  98. }
  99. return hash
  100. }
  101. hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) {
  102. hash: [32]byte
  103. if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok {
  104. _blake2.init_odin(&c)
  105. buf := make([]byte, 512)
  106. defer delete(buf)
  107. read := 1
  108. for read > 0 {
  109. read, _ = fs->impl_read(buf)
  110. if read > 0 {
  111. _blake2.update_odin(&c, buf[:read])
  112. }
  113. }
  114. _blake2.blake2s_final_odin(&c, hash[:])
  115. return hash, true
  116. } else {
  117. return hash, false
  118. }
  119. }
  120. hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
  121. if !load_at_once {
  122. return hash_stream_odin(ctx, os.stream_from_handle(hd))
  123. } else {
  124. if buf, ok := os.read_entire_file(hd); ok {
  125. return hash_bytes_odin(ctx, buf[:]), ok
  126. }
  127. }
  128. return [32]byte{}, false
  129. }
  130. @(private)
  131. _create_blake2s_ctx :: #force_inline proc() {
  132. ctx: _blake2.Blake2s_Context
  133. cfg: _blake2.Blake2_Config
  134. cfg.size = _blake2.BLAKE2S_SIZE
  135. ctx.cfg = cfg
  136. _hash_impl.internal_ctx = ctx
  137. _hash_impl.hash_size = ._32
  138. }
  139. @(private)
  140. _init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) {
  141. _create_blake2s_ctx()
  142. if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok {
  143. _blake2.init_odin(&c)
  144. }
  145. }
  146. @(private)
  147. _update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) {
  148. if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok {
  149. _blake2.update_odin(&c, data)
  150. }
  151. }
  152. @(private)
  153. _final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
  154. if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok {
  155. _blake2.blake2s_final_odin(&c, hash)
  156. }
  157. }