uncle_blake3 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.md +27 -0
- data/README.md +89 -0
- data/ext/Rakefile +55 -0
- data/ext/binding/uncle_blake3.c +41 -0
- data/ext/blake3/c/Makefile.testing +82 -0
- data/ext/blake3/c/README.md +316 -0
- data/ext/blake3/c/blake3.c +616 -0
- data/ext/blake3/c/blake3.h +60 -0
- data/ext/blake3/c/blake3_avx2.c +326 -0
- data/ext/blake3/c/blake3_avx2_x86-64_unix.S +1815 -0
- data/ext/blake3/c/blake3_avx2_x86-64_windows_gnu.S +1817 -0
- data/ext/blake3/c/blake3_avx2_x86-64_windows_msvc.asm +1828 -0
- data/ext/blake3/c/blake3_avx512.c +1207 -0
- data/ext/blake3/c/blake3_avx512_x86-64_unix.S +2585 -0
- data/ext/blake3/c/blake3_avx512_x86-64_windows_gnu.S +2615 -0
- data/ext/blake3/c/blake3_avx512_x86-64_windows_msvc.asm +2634 -0
- data/ext/blake3/c/blake3_dispatch.c +276 -0
- data/ext/blake3/c/blake3_impl.h +282 -0
- data/ext/blake3/c/blake3_neon.c +351 -0
- data/ext/blake3/c/blake3_portable.c +160 -0
- data/ext/blake3/c/blake3_sse2.c +566 -0
- data/ext/blake3/c/blake3_sse2_x86-64_unix.S +2291 -0
- data/ext/blake3/c/blake3_sse2_x86-64_windows_gnu.S +2332 -0
- data/ext/blake3/c/blake3_sse2_x86-64_windows_msvc.asm +2350 -0
- data/ext/blake3/c/blake3_sse41.c +560 -0
- data/ext/blake3/c/blake3_sse41_x86-64_unix.S +2028 -0
- data/ext/blake3/c/blake3_sse41_x86-64_windows_gnu.S +2069 -0
- data/ext/blake3/c/blake3_sse41_x86-64_windows_msvc.asm +2089 -0
- data/ext/blake3/c/example.c +37 -0
- data/ext/blake3/c/main.c +166 -0
- data/ext/blake3/c/test.py +97 -0
- data/lib/uncle_blake3/binding.rb +20 -0
- data/lib/uncle_blake3/build/loader.rb +40 -0
- data/lib/uncle_blake3/build/platform.rb +37 -0
- data/lib/uncle_blake3/build.rb +4 -0
- data/lib/uncle_blake3/digest.rb +119 -0
- data/lib/uncle_blake3/version.rb +5 -0
- data/lib/uncle_blake3.rb +7 -0
- metadata +112 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
#include "blake3.h"
|
2
|
+
#include <errno.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include <unistd.h>
|
7
|
+
|
8
|
+
int main() {
|
9
|
+
// Initialize the hasher.
|
10
|
+
blake3_hasher hasher;
|
11
|
+
blake3_hasher_init(&hasher);
|
12
|
+
|
13
|
+
// Read input bytes from stdin.
|
14
|
+
unsigned char buf[65536];
|
15
|
+
while (1) {
|
16
|
+
ssize_t n = read(STDIN_FILENO, buf, sizeof(buf));
|
17
|
+
if (n > 0) {
|
18
|
+
blake3_hasher_update(&hasher, buf, n);
|
19
|
+
} else if (n == 0) {
|
20
|
+
break; // end of file
|
21
|
+
} else {
|
22
|
+
fprintf(stderr, "read failed: %s\n", strerror(errno));
|
23
|
+
exit(1);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
// Finalize the hash. BLAKE3_OUT_LEN is the default output length, 32 bytes.
|
28
|
+
uint8_t output[BLAKE3_OUT_LEN];
|
29
|
+
blake3_hasher_finalize(&hasher, output, BLAKE3_OUT_LEN);
|
30
|
+
|
31
|
+
// Print the hash as hexadecimal.
|
32
|
+
for (size_t i = 0; i < BLAKE3_OUT_LEN; i++) {
|
33
|
+
printf("%02x", output[i]);
|
34
|
+
}
|
35
|
+
printf("\n");
|
36
|
+
return 0;
|
37
|
+
}
|
data/ext/blake3/c/main.c
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
/*
|
2
|
+
* This main file is intended for testing via `make test`. It does not build in
|
3
|
+
* other settings. See README.md in this directory for examples of how to build
|
4
|
+
* C code.
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include <assert.h>
|
8
|
+
#include <errno.h>
|
9
|
+
#include <stdbool.h>
|
10
|
+
#include <stdint.h>
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <stdlib.h>
|
13
|
+
|
14
|
+
#include "blake3.h"
|
15
|
+
#include "blake3_impl.h"
|
16
|
+
|
17
|
+
#define HASH_MODE 0
|
18
|
+
#define KEYED_HASH_MODE 1
|
19
|
+
#define DERIVE_KEY_MODE 2
|
20
|
+
|
21
|
+
static void hex_char_value(uint8_t c, uint8_t *value, bool *valid) {
|
22
|
+
if ('0' <= c && c <= '9') {
|
23
|
+
*value = c - '0';
|
24
|
+
*valid = true;
|
25
|
+
} else if ('a' <= c && c <= 'f') {
|
26
|
+
*value = 10 + c - 'a';
|
27
|
+
*valid = true;
|
28
|
+
} else {
|
29
|
+
*valid = false;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
static int parse_key(char *hex_key, uint8_t out[BLAKE3_KEY_LEN]) {
|
34
|
+
size_t hex_len = strlen(hex_key);
|
35
|
+
if (hex_len != 64) {
|
36
|
+
fprintf(stderr, "Expected a 64-char hexadecimal key, got %zu chars.\n",
|
37
|
+
hex_len);
|
38
|
+
return 1;
|
39
|
+
}
|
40
|
+
for (size_t i = 0; i < 64; i++) {
|
41
|
+
uint8_t value;
|
42
|
+
bool valid;
|
43
|
+
hex_char_value(hex_key[i], &value, &valid);
|
44
|
+
if (!valid) {
|
45
|
+
fprintf(stderr, "Invalid hex char.\n");
|
46
|
+
return 1;
|
47
|
+
}
|
48
|
+
if (i % 2 == 0) {
|
49
|
+
out[i / 2] = 0;
|
50
|
+
value <<= 4;
|
51
|
+
}
|
52
|
+
out[i / 2] += value;
|
53
|
+
}
|
54
|
+
return 0;
|
55
|
+
}
|
56
|
+
|
57
|
+
/* A little repetition here */
|
58
|
+
enum cpu_feature {
|
59
|
+
SSE2 = 1 << 0,
|
60
|
+
SSSE3 = 1 << 1,
|
61
|
+
SSE41 = 1 << 2,
|
62
|
+
AVX = 1 << 3,
|
63
|
+
AVX2 = 1 << 4,
|
64
|
+
AVX512F = 1 << 5,
|
65
|
+
AVX512VL = 1 << 6,
|
66
|
+
/* ... */
|
67
|
+
UNDEFINED = 1 << 30
|
68
|
+
};
|
69
|
+
|
70
|
+
extern enum cpu_feature g_cpu_features;
|
71
|
+
enum cpu_feature get_cpu_features(void);
|
72
|
+
|
73
|
+
int main(int argc, char **argv) {
|
74
|
+
size_t out_len = BLAKE3_OUT_LEN;
|
75
|
+
uint8_t key[BLAKE3_KEY_LEN];
|
76
|
+
char *context = "";
|
77
|
+
uint8_t mode = HASH_MODE;
|
78
|
+
while (argc > 1) {
|
79
|
+
if (argc <= 2) {
|
80
|
+
fprintf(stderr, "Odd number of arguments.\n");
|
81
|
+
return 1;
|
82
|
+
}
|
83
|
+
if (strcmp("--length", argv[1]) == 0) {
|
84
|
+
char *endptr = NULL;
|
85
|
+
errno = 0;
|
86
|
+
unsigned long long out_len_ll = strtoull(argv[2], &endptr, 10);
|
87
|
+
if (errno != 0 || out_len_ll > SIZE_MAX || endptr == argv[2] ||
|
88
|
+
*endptr != 0) {
|
89
|
+
fprintf(stderr, "Bad length argument.\n");
|
90
|
+
return 1;
|
91
|
+
}
|
92
|
+
out_len = (size_t)out_len_ll;
|
93
|
+
} else if (strcmp("--keyed", argv[1]) == 0) {
|
94
|
+
mode = KEYED_HASH_MODE;
|
95
|
+
int ret = parse_key(argv[2], key);
|
96
|
+
if (ret != 0) {
|
97
|
+
return ret;
|
98
|
+
}
|
99
|
+
} else if (strcmp("--derive-key", argv[1]) == 0) {
|
100
|
+
mode = DERIVE_KEY_MODE;
|
101
|
+
context = argv[2];
|
102
|
+
} else {
|
103
|
+
fprintf(stderr, "Unknown flag.\n");
|
104
|
+
return 1;
|
105
|
+
}
|
106
|
+
argc -= 2;
|
107
|
+
argv += 2;
|
108
|
+
}
|
109
|
+
|
110
|
+
/*
|
111
|
+
* We're going to hash the input multiple times, so we need to buffer it all.
|
112
|
+
* This is just for test cases, so go ahead and assume that the input is less
|
113
|
+
* than 1 MiB.
|
114
|
+
*/
|
115
|
+
size_t buf_capacity = 1 << 20;
|
116
|
+
uint8_t *buf = malloc(buf_capacity);
|
117
|
+
assert(buf != NULL);
|
118
|
+
size_t buf_len = 0;
|
119
|
+
while (1) {
|
120
|
+
size_t n = fread(&buf[buf_len], 1, buf_capacity - buf_len, stdin);
|
121
|
+
if (n == 0) {
|
122
|
+
break;
|
123
|
+
}
|
124
|
+
buf_len += n;
|
125
|
+
assert(buf_len < buf_capacity);
|
126
|
+
}
|
127
|
+
|
128
|
+
const int mask = get_cpu_features();
|
129
|
+
int feature = 0;
|
130
|
+
do {
|
131
|
+
fprintf(stderr, "Testing 0x%08X\n", feature);
|
132
|
+
g_cpu_features = feature;
|
133
|
+
blake3_hasher hasher;
|
134
|
+
switch (mode) {
|
135
|
+
case HASH_MODE:
|
136
|
+
blake3_hasher_init(&hasher);
|
137
|
+
break;
|
138
|
+
case KEYED_HASH_MODE:
|
139
|
+
blake3_hasher_init_keyed(&hasher, key);
|
140
|
+
break;
|
141
|
+
case DERIVE_KEY_MODE:
|
142
|
+
blake3_hasher_init_derive_key(&hasher, context);
|
143
|
+
break;
|
144
|
+
default:
|
145
|
+
abort();
|
146
|
+
}
|
147
|
+
|
148
|
+
blake3_hasher_update(&hasher, buf, buf_len);
|
149
|
+
|
150
|
+
/* TODO: An incremental output reader API to avoid this allocation. */
|
151
|
+
uint8_t *out = malloc(out_len);
|
152
|
+
if (out_len > 0 && out == NULL) {
|
153
|
+
fprintf(stderr, "malloc() failed.\n");
|
154
|
+
return 1;
|
155
|
+
}
|
156
|
+
blake3_hasher_finalize(&hasher, out, out_len);
|
157
|
+
for (size_t i = 0; i < out_len; i++) {
|
158
|
+
printf("%02x", out[i]);
|
159
|
+
}
|
160
|
+
printf("\n");
|
161
|
+
free(out);
|
162
|
+
feature = (feature - mask) & mask;
|
163
|
+
} while (feature != 0);
|
164
|
+
free(buf);
|
165
|
+
return 0;
|
166
|
+
}
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
|
3
|
+
from binascii import hexlify
|
4
|
+
import json
|
5
|
+
from os import path
|
6
|
+
import subprocess
|
7
|
+
|
8
|
+
HERE = path.dirname(__file__)
|
9
|
+
TEST_VECTORS_PATH = path.join(HERE, "..", "test_vectors", "test_vectors.json")
|
10
|
+
TEST_VECTORS = json.load(open(TEST_VECTORS_PATH))
|
11
|
+
|
12
|
+
|
13
|
+
def run_blake3(args, input):
|
14
|
+
output = subprocess.run([path.join(HERE, "blake3")] + args,
|
15
|
+
input=input,
|
16
|
+
stdout=subprocess.PIPE,
|
17
|
+
check=True)
|
18
|
+
return output.stdout.decode().strip()
|
19
|
+
|
20
|
+
|
21
|
+
# Fill the input with a repeating byte pattern. We use a cycle length of 251,
|
22
|
+
# because that's the largets prime number less than 256. This makes it unlikely
|
23
|
+
# to swapping any two adjacent input blocks or chunks will give the same
|
24
|
+
# answer.
|
25
|
+
def make_test_input(length):
|
26
|
+
i = 0
|
27
|
+
buf = bytearray()
|
28
|
+
while len(buf) < length:
|
29
|
+
buf.append(i)
|
30
|
+
i = (i + 1) % 251
|
31
|
+
return buf
|
32
|
+
|
33
|
+
|
34
|
+
def main():
|
35
|
+
for case in TEST_VECTORS["cases"]:
|
36
|
+
input_len = case["input_len"]
|
37
|
+
input = make_test_input(input_len)
|
38
|
+
hex_key = hexlify(TEST_VECTORS["key"].encode())
|
39
|
+
context_string = TEST_VECTORS["context_string"]
|
40
|
+
expected_hash_xof = case["hash"]
|
41
|
+
expected_hash = expected_hash_xof[:64]
|
42
|
+
expected_keyed_hash_xof = case["keyed_hash"]
|
43
|
+
expected_keyed_hash = expected_keyed_hash_xof[:64]
|
44
|
+
expected_derive_key_xof = case["derive_key"]
|
45
|
+
expected_derive_key = expected_derive_key_xof[:64]
|
46
|
+
|
47
|
+
# Test the default hash.
|
48
|
+
test_hash = run_blake3([], input)
|
49
|
+
for line in test_hash.splitlines():
|
50
|
+
assert expected_hash == line, \
|
51
|
+
"hash({}): {} != {}".format(input_len, expected_hash, line)
|
52
|
+
|
53
|
+
# Test the extended hash.
|
54
|
+
xof_len = len(expected_hash_xof) // 2
|
55
|
+
test_hash_xof = run_blake3(["--length", str(xof_len)], input)
|
56
|
+
for line in test_hash_xof.splitlines():
|
57
|
+
assert expected_hash_xof == line, \
|
58
|
+
"hash_xof({}): {} != {}".format(
|
59
|
+
input_len, expected_hash_xof, line)
|
60
|
+
|
61
|
+
# Test the default keyed hash.
|
62
|
+
test_keyed_hash = run_blake3(["--keyed", hex_key], input)
|
63
|
+
for line in test_keyed_hash.splitlines():
|
64
|
+
assert expected_keyed_hash == line, \
|
65
|
+
"keyed_hash({}): {} != {}".format(
|
66
|
+
input_len, expected_keyed_hash, line)
|
67
|
+
|
68
|
+
# Test the extended keyed hash.
|
69
|
+
xof_len = len(expected_keyed_hash_xof) // 2
|
70
|
+
test_keyed_hash_xof = run_blake3(
|
71
|
+
["--keyed", hex_key, "--length",
|
72
|
+
str(xof_len)], input)
|
73
|
+
for line in test_keyed_hash_xof.splitlines():
|
74
|
+
assert expected_keyed_hash_xof == line, \
|
75
|
+
"keyed_hash_xof({}): {} != {}".format(
|
76
|
+
input_len, expected_keyed_hash_xof, line)
|
77
|
+
|
78
|
+
# Test the default derive key.
|
79
|
+
test_derive_key = run_blake3(["--derive-key", context_string], input)
|
80
|
+
for line in test_derive_key.splitlines():
|
81
|
+
assert expected_derive_key == line, \
|
82
|
+
"derive_key({}): {} != {}".format(
|
83
|
+
input_len, expected_derive_key, line)
|
84
|
+
|
85
|
+
# Test the extended derive key.
|
86
|
+
xof_len = len(expected_derive_key_xof) // 2
|
87
|
+
test_derive_key_xof = run_blake3(
|
88
|
+
["--derive-key", context_string, "--length",
|
89
|
+
str(xof_len)], input)
|
90
|
+
for line in test_derive_key_xof.splitlines():
|
91
|
+
assert expected_derive_key_xof == line, \
|
92
|
+
"derive_key_xof({}): {} != {}".format(
|
93
|
+
input_len, expected_derive_key_xof, line)
|
94
|
+
|
95
|
+
|
96
|
+
if __name__ == "__main__":
|
97
|
+
main()
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'build/loader'
|
4
|
+
|
5
|
+
module UncleBlake3
|
6
|
+
module Binding
|
7
|
+
extend ::FFI::Library
|
8
|
+
ffi_lib Build::Loader.find('UncleBlake3')
|
9
|
+
|
10
|
+
attach_function :key_length, :UncleBlake3_KEY_LEN, %i[], :uint16
|
11
|
+
attach_function :default_output_length, :UncleBlake3_OUT_LEN, %i[], :uint16
|
12
|
+
|
13
|
+
attach_function :init, :UncleBlake3_Init, %i[], :pointer
|
14
|
+
attach_function :init_with_key, :UncleBlake3_InitWithKey, %i[pointer], :pointer
|
15
|
+
attach_function :init_with_key_seed, :UncleBlake3_InitWithKeySeed, %i[pointer size_t], :pointer
|
16
|
+
attach_function :update, :UncleBlake3_Update, %i[pointer pointer size_t], :int
|
17
|
+
attach_function :final, :UncleBlake3_Final, %i[pointer pointer size_t], :int
|
18
|
+
attach_function :destroy, :UncleBlake3_Destroy, %i[pointer], :void
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ffi'
|
4
|
+
require 'pathname'
|
5
|
+
require_relative 'platform'
|
6
|
+
|
7
|
+
module UncleBlake3
|
8
|
+
module Build
|
9
|
+
# taken from:
|
10
|
+
# https://github.com/ffi/ffi-compiler/blob/master/lib/ffi-compiler/loader.rb
|
11
|
+
module Loader
|
12
|
+
def self.find(name, start_path = nil)
|
13
|
+
library = Platform.instance.map_library_name(name)
|
14
|
+
root = false
|
15
|
+
::Pathname.new(start_path || caller_path(caller[0])).ascend do |path|
|
16
|
+
Dir.glob("#{path}/**/{#{::FFI::Platform::ARCH}-#{::FFI::Platform::OS}/#{library},#{library}}") do |f|
|
17
|
+
return f
|
18
|
+
end
|
19
|
+
|
20
|
+
break if root
|
21
|
+
|
22
|
+
# Next iteration will be the root of the gem if this is the lib/ dir - stop after that
|
23
|
+
root = ::File.basename(path) == 'lib'
|
24
|
+
end
|
25
|
+
raise ::LoadError, "cannot find '#{name}' library"
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.caller_path(line = caller[0])
|
29
|
+
if ::FFI::Platform::OS == 'windows'
|
30
|
+
drive = line[0..1]
|
31
|
+
path = line[2..].split(/:/)[0]
|
32
|
+
full_path = drive + path
|
33
|
+
else
|
34
|
+
full_path = line.split(/:/)[0]
|
35
|
+
end
|
36
|
+
::File.dirname full_path
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ffi'
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
module UncleBlake3
|
7
|
+
module Build
|
8
|
+
# mostly taken from:
|
9
|
+
# https://github.com/ffi/ffi-compiler/blob/master/lib/ffi-compiler/platform.rb
|
10
|
+
|
11
|
+
class Platform
|
12
|
+
include ::Singleton
|
13
|
+
|
14
|
+
LIBSUFFIX = ::FFI::Platform.mac? ? 'bundle' : ::FFI::Platform::LIBSUFFIX
|
15
|
+
|
16
|
+
def map_library_name(name)
|
17
|
+
"#{::FFI::Platform::LIBPREFIX}#{name}.#{LIBSUFFIX}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def arch
|
21
|
+
::FFI::Platform::ARCH
|
22
|
+
end
|
23
|
+
|
24
|
+
def os
|
25
|
+
::FFI::Platform::OS
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
::FFI::Platform.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def mac?
|
33
|
+
::FFI::Platform.mac?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'ffi'
|
5
|
+
require 'objspace'
|
6
|
+
require_relative 'binding'
|
7
|
+
|
8
|
+
module UncleBlake3
|
9
|
+
class Digest
|
10
|
+
KEY_LENGTH = Binding.key_length
|
11
|
+
DEFAULT_OUTPUT_LENGTH = Binding.default_output_length
|
12
|
+
|
13
|
+
module Error
|
14
|
+
end
|
15
|
+
|
16
|
+
class ArgumentError < ::ArgumentError
|
17
|
+
include Error
|
18
|
+
end
|
19
|
+
|
20
|
+
class TypeError < ::TypeError
|
21
|
+
include Error
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(output_length: DEFAULT_OUTPUT_LENGTH, key: nil, key_seed: nil)
|
25
|
+
raise TypeError, 'Hash length is not an Integer' unless output_length.is_a?(::Integer)
|
26
|
+
raise ArgumentError, 'Hash length out of range' unless (1...(1 << 20)).include?(output_length)
|
27
|
+
raise TypeError, 'Key is not a String' if !key.nil? && !key.is_a?(::String)
|
28
|
+
raise ArgumentError, 'Key length mismatched' unless key.nil? || (key.bytesize == KEY_LENGTH)
|
29
|
+
raise TypeError, 'Key seed is not a String' if !key_seed.nil? && !key_seed.is_a?(::String)
|
30
|
+
@native_instance = if !key && !key_seed
|
31
|
+
Binding.init
|
32
|
+
elsif key && key_seed
|
33
|
+
raise ::ArgumentError, 'Both key and key_seed available at the same time; please pick only one.'
|
34
|
+
elsif key
|
35
|
+
key_buffer = ::FFI::MemoryPointer.new(:uint8, KEY_LENGTH)
|
36
|
+
key_buffer.put_bytes(0, key)
|
37
|
+
Binding.init_with_key(key_buffer)
|
38
|
+
elsif key_seed
|
39
|
+
seed_size = key_seed.bytesize
|
40
|
+
seed_buffer = ::FFI::MemoryPointer.new(:uint8, seed_size)
|
41
|
+
seed_buffer.put_bytes(0, key_seed)
|
42
|
+
Binding.init_with_key_seed(seed_buffer, seed_size)
|
43
|
+
else
|
44
|
+
raise ::ArgumentError, 'Unknown mode of operation'
|
45
|
+
end.tap do |pointer|
|
46
|
+
::ObjectSpace.define_finalizer(self, self.class._create_finalizer(pointer))
|
47
|
+
end
|
48
|
+
@output_length = output_length
|
49
|
+
invalidate_cache
|
50
|
+
end
|
51
|
+
|
52
|
+
def update(data)
|
53
|
+
data_size = data.bytesize
|
54
|
+
data_buffer = ::FFI::MemoryPointer.new(:uint8, data_size)
|
55
|
+
data_buffer.put_bytes(0, data)
|
56
|
+
Binding.update(@native_instance, data_buffer, data_size)
|
57
|
+
self
|
58
|
+
ensure
|
59
|
+
invalidate_cache
|
60
|
+
end
|
61
|
+
|
62
|
+
def <<(*args, **kwargs)
|
63
|
+
update(*args, **kwargs)
|
64
|
+
end
|
65
|
+
|
66
|
+
def digest
|
67
|
+
@_digest_cache ||= begin
|
68
|
+
data_buffer = ::FFI::MemoryPointer.new(:uint8, @output_length)
|
69
|
+
Binding.final(@native_instance, data_buffer, @output_length)
|
70
|
+
data_buffer.get_bytes(0, @output_length)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def hexdigest
|
75
|
+
@_hexdigest_cache ||= digest.unpack1('H*')
|
76
|
+
end
|
77
|
+
|
78
|
+
def base64digest
|
79
|
+
@_base64digest_cache ||= ::Base64.strict_encode64(digest)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def invalidate_cache
|
85
|
+
@_digest_cache = nil
|
86
|
+
@_hexdigest_cache = nil
|
87
|
+
@_base64digest_cache = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
class << self
|
91
|
+
# https://www.mikeperham.com/2010/02/24/the-trouble-with-ruby-finalizers/
|
92
|
+
def _create_finalizer(instance)
|
93
|
+
proc {
|
94
|
+
Binding.destroy(instance)
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def digest(*args, **kwargs)
|
99
|
+
_generic_digest(*args, **kwargs, &:digest)
|
100
|
+
end
|
101
|
+
|
102
|
+
def hexdigest(*args, **kwargs)
|
103
|
+
_generic_digest(*args, **kwargs, &:hexdigest)
|
104
|
+
end
|
105
|
+
|
106
|
+
def base64digest(*args, **kwargs)
|
107
|
+
_generic_digest(*args, **kwargs, &:base64digest)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def _generic_digest(data, output_length: nil, key: nil, key_seed: nil, &hash_finalizer)
|
113
|
+
instance = new(**{ output_length: output_length, key: key, key_seed: key_seed }.compact)
|
114
|
+
instance.update(data)
|
115
|
+
hash_finalizer.call(instance)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/uncle_blake3.rb
ADDED
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: uncle_blake3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sarun Rattanasiri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-02-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.15.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.15.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 13.0.6
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 13.0.6
|
41
|
+
description: This gem brought the hash algorithm, Blake3, to Ruby. It uses the official
|
42
|
+
Blake3 implementation which optimized and maintained by the original Blake3 team
|
43
|
+
themselves.
|
44
|
+
email: midnight_w@gmx.tw
|
45
|
+
executables: []
|
46
|
+
extensions:
|
47
|
+
- ext/Rakefile
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- LICENSE.md
|
51
|
+
- README.md
|
52
|
+
- ext/Rakefile
|
53
|
+
- ext/binding/uncle_blake3.c
|
54
|
+
- ext/blake3/c/Makefile.testing
|
55
|
+
- ext/blake3/c/README.md
|
56
|
+
- ext/blake3/c/blake3.c
|
57
|
+
- ext/blake3/c/blake3.h
|
58
|
+
- ext/blake3/c/blake3_avx2.c
|
59
|
+
- ext/blake3/c/blake3_avx2_x86-64_unix.S
|
60
|
+
- ext/blake3/c/blake3_avx2_x86-64_windows_gnu.S
|
61
|
+
- ext/blake3/c/blake3_avx2_x86-64_windows_msvc.asm
|
62
|
+
- ext/blake3/c/blake3_avx512.c
|
63
|
+
- ext/blake3/c/blake3_avx512_x86-64_unix.S
|
64
|
+
- ext/blake3/c/blake3_avx512_x86-64_windows_gnu.S
|
65
|
+
- ext/blake3/c/blake3_avx512_x86-64_windows_msvc.asm
|
66
|
+
- ext/blake3/c/blake3_dispatch.c
|
67
|
+
- ext/blake3/c/blake3_impl.h
|
68
|
+
- ext/blake3/c/blake3_neon.c
|
69
|
+
- ext/blake3/c/blake3_portable.c
|
70
|
+
- ext/blake3/c/blake3_sse2.c
|
71
|
+
- ext/blake3/c/blake3_sse2_x86-64_unix.S
|
72
|
+
- ext/blake3/c/blake3_sse2_x86-64_windows_gnu.S
|
73
|
+
- ext/blake3/c/blake3_sse2_x86-64_windows_msvc.asm
|
74
|
+
- ext/blake3/c/blake3_sse41.c
|
75
|
+
- ext/blake3/c/blake3_sse41_x86-64_unix.S
|
76
|
+
- ext/blake3/c/blake3_sse41_x86-64_windows_gnu.S
|
77
|
+
- ext/blake3/c/blake3_sse41_x86-64_windows_msvc.asm
|
78
|
+
- ext/blake3/c/example.c
|
79
|
+
- ext/blake3/c/main.c
|
80
|
+
- ext/blake3/c/test.py
|
81
|
+
- lib/uncle_blake3.rb
|
82
|
+
- lib/uncle_blake3/binding.rb
|
83
|
+
- lib/uncle_blake3/build.rb
|
84
|
+
- lib/uncle_blake3/build/loader.rb
|
85
|
+
- lib/uncle_blake3/build/platform.rb
|
86
|
+
- lib/uncle_blake3/digest.rb
|
87
|
+
- lib/uncle_blake3/version.rb
|
88
|
+
homepage: https://github.com/the-cave/uncle-blake3
|
89
|
+
licenses: []
|
90
|
+
metadata:
|
91
|
+
homepage_uri: https://github.com/the-cave/uncle-blake3
|
92
|
+
source_code_uri: https://github.com/the-cave/uncle-blake3/tree/v0.0.1
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.6.0
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubygems_version: 3.2.32
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: A binding of the Blake3 hash algorithm for Ruby
|
112
|
+
test_files: []
|