uncle_blake3 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|