From 16c176dc89ee4557a3e86803434de6d5f07d55f4 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Mon, 23 Oct 2023 22:03:06 +0200 Subject: [PATCH 001/160] Implement new union intrinsics and add support for len/cap --- src/check_builtin.cpp | 139 +++++++++++++++++++++++++++++++++- src/checker_builtin_procs.hpp | 10 ++- 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 49095a7a8..8fae04b6e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1780,7 +1780,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; - } + } else if (is_type_union(op_type)) { + Type *u = base_type(op_type); + mode = Addressing_Constant; + value = exact_value_i64(u->Union.variants.count); + type = t_untyped_integer; + } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; } @@ -5117,6 +5122,138 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_union_tag: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Type; + operand->type = union_tag_type(u); + } + break; + + case BuiltinProc_type_union_tag_offset: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + // NOTE(jakubtomsu): forces calculation of variant_block_size + type_size_of(u); + i64 tag_offset = u->Union.variant_block_size; + GB_ASSERT(tag_offset > 0); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(tag_offset); + } + break; + + case BuiltinProc_type_variant_type: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + Operand x = {}; + check_expr_or_type(c, &x, ce->args[1]); + if (!is_type_integer(x.type) || x.mode != Addressing_Constant) { + error(call, "Expected a constant integer for '%.*s", LIT(builtin_name)); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + + i64 index = big_int_to_i64(&x.value.value_integer); + if (u->Union.kind != UnionType_no_nil) { + index -= 1; + } + + if (index < 0 || index >= u->Union.variants.count) { + error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name)); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + + operand->mode = Addressing_Type; + operand->type = u->Union.variants[index]; + } + break; + + case BuiltinProc_type_variant_tag: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *v = check_type(c, ce->args[1]); + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(union_variant_index(u, v)); + } + break; + case BuiltinProc_type_struct_field_count: operand->value = exact_value_i64(0); if (operand->mode != Addressing_Type) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c89ab2429..c5d10955b 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -260,6 +260,10 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_specialization_of, BuiltinProc_type_is_variant_of, + BuiltinProc_type_union_tag, + BuiltinProc_type_union_tag_offset, + BuiltinProc_type_variant_type, + BuiltinProc_type_variant_tag, BuiltinProc_type_struct_field_count, @@ -557,7 +561,11 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_tag"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From c76ab138eb574f271dff7b029ee8df2a1a6c7481 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Tue, 24 Oct 2023 22:15:33 +0200 Subject: [PATCH 002/160] Naming, use variant index instead of tag --- core/intrinsics/intrinsics.odin | 5 +++++ src/checker_builtin_procs.hpp | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 33c4e2b07..505309a8e 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -162,7 +162,12 @@ type_is_matrix :: proc($T: typeid) -> bool --- type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- + type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- +type_union_tag :: proc($U: typeid) -> typeid where type_is_union(U) --- +type_union_tag_offset :: proc($U: typeid) -> int where type_is_union(U) --- +type_variant_type_of_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- +type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- type_field_type :: proc($T: typeid, $name: string) -> typeid --- diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c5d10955b..8053d54f2 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -262,8 +262,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_variant_of, BuiltinProc_type_union_tag, BuiltinProc_type_union_tag_offset, - BuiltinProc_type_variant_type, - BuiltinProc_type_variant_tag, + BuiltinProc_type_variant_type_of, + BuiltinProc_type_variant_index_of, BuiltinProc_type_struct_field_count, @@ -564,8 +564,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_union_tag"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_tag"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From f7e05162547c9444261a215992ea3c39f22a90b6 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:47:18 +0200 Subject: [PATCH 003/160] Fix the intrinsics, add min and max --- src/check_builtin.cpp | 46 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8fae04b6e..a26ac4baa 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2597,7 +2597,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2662,6 +2662,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.min_value; return true; + } else if (is_type_union(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + i64 min_tag = bt->Union.kind == UnionType_no_nil ? 0 : 1; + operand->value = exact_value_i64(min_tag); + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'min', got %s", type_str); @@ -2766,7 +2774,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2836,6 +2844,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.max_value; return true; + } else if (is_type_union(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + i64 max_tag = (bt->Union.kind == UnionType_no_nil ? 0 : 1) + bt->Union.variants.count - 1; + operand->value = exact_value_i64(max_tag); + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'max', got %s", type_str); @@ -5180,7 +5196,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_variant_type: + case BuiltinProc_type_variant_type_of: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); @@ -5210,10 +5226,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } i64 index = big_int_to_i64(&x.value.value_integer); - if (u->Union.kind != UnionType_no_nil) { - index -= 1; - } - if (index < 0 || index >= u->Union.variants.count) { error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name)); operand->mode = Addressing_Type; @@ -5226,7 +5238,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_variant_tag: + case BuiltinProc_type_variant_index_of: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); @@ -5247,10 +5259,26 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *v = check_type(c, ce->args[1]); u = base_type(u); GB_ASSERT(u->kind == Type_Union); + + i64 index = -1; + for_array(i, u->Union.variants) { + Type *vt = u->Union.variants[i]; + if (union_variant_index_types_equal(v, vt)) { + index = i64(i); + break; + } + } + + if (index < 0) { + error(operand->expr, "Expected a variant type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } operand->mode = Addressing_Constant; operand->type = t_untyped_integer; - operand->value = exact_value_i64(union_variant_index(u, v)); + operand->value = exact_value_i64(index); } break; From 2f8d60ec47b32206172839c2d96b66cb872985be Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 17:33:27 +0200 Subject: [PATCH 004/160] Fix indentation --- src/check_builtin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a26ac4baa..7cadf49a0 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1781,11 +1781,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; } else if (is_type_union(op_type)) { - Type *u = base_type(op_type); + Type *u = base_type(op_type); mode = Addressing_Constant; value = exact_value_i64(u->Union.variants.count); type = t_untyped_integer; - } + } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; } From 625cb032841c86d046d0ceb8123936bd393785ea Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:23:24 +0200 Subject: [PATCH 005/160] Rename type_union_tag to type_union_tag_type --- core/intrinsics/intrinsics.odin | 4 +- src/check_builtin.cpp | 2 +- src/checker_builtin_procs.hpp | 4 +- test.odin | 272 ++++++++++++++++++++++++++++++++ 4 files changed, 277 insertions(+), 5 deletions(-) create mode 100644 test.odin diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 505309a8e..62f3d1ad2 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -164,9 +164,9 @@ type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- -type_union_tag :: proc($U: typeid) -> typeid where type_is_union(U) --- +type_union_tag_type :: proc($U: typeid) -> typeid where type_is_union(U) --- type_union_tag_offset :: proc($U: typeid) -> int where type_is_union(U) --- -type_variant_type_of_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- +type_variant_type_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7cadf49a0..5907b30e3 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5138,7 +5138,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_union_tag: + case BuiltinProc_type_union_tag_type: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 8053d54f2..35ca9c51e 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -260,7 +260,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_specialization_of, BuiltinProc_type_is_variant_of, - BuiltinProc_type_union_tag, + BuiltinProc_type_union_tag_type, BuiltinProc_type_union_tag_offset, BuiltinProc_type_variant_type_of, BuiltinProc_type_variant_index_of, @@ -562,7 +562,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/test.odin b/test.odin new file mode 100644 index 000000000..0930184ac --- /dev/null +++ b/test.odin @@ -0,0 +1,272 @@ +package test + +import "core:fmt" +import "core:intrinsics" +import "core:mem" +import "core:reflect" +import "core:runtime" +import "core:slice" + +// TODO: extend for loops? + +get_tag :: proc(u: $T) -> int where intrinsics.type_is_union(T) { + u := u + return int( + (cast(^intrinsics.type_union_tag_type(T))(uintptr(&u) + + intrinsics.type_union_tag_offset(T)))^, + ) +} + +set_tag :: proc(u: ^$T, tag: int) where intrinsics.type_is_union(T) { + TAG :: intrinsics.type_union_tag_type(T) + (cast(^TAG)(uintptr(u) + intrinsics.type_union_tag_offset(T)))^ = TAG(tag) +} + +get_variant_index :: proc(u: $T) -> int where intrinsics.type_is_union(T) { + return min(T) + get_tag(u) +} + +main :: proc() { + Foo :: union { + f32, // 1 + u16, // 2 + u8, // 3 + } + + fmt.println(typeid_of(Foo)) + fmt.println("size_of:", size_of(Foo)) + fmt.println("len:", len(Foo)) + fmt.println("cap:", cap(Foo)) + fmt.println("min:", min(Foo)) + fmt.println("max:", max(Foo)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Foo))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Foo)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Foo, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Foo, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Foo, 2))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Foo, f32)) + fmt.println("index of u16:", intrinsics.type_variant_index_of(Foo, u16)) + fmt.println("index of u8 :", intrinsics.type_variant_index_of(Foo, u8)) + // Goofy test of unsafe tag manipulation + foo: Foo = u16(255 + 255 << 8) + assert(get_tag(foo) == 2) + fmt.println(foo) + set_tag(&foo, 3) + assert(get_tag(foo) == 3) + fmt.println(foo) + fmt.println() + + Bar :: union #no_nil { + i8, // 0 + u8, // 1 + b8, // 2 + } + + fmt.println(typeid_of(Bar)) + fmt.println("size_of:", size_of(Bar)) + fmt.println("len:", len(Bar)) + fmt.println("cap:", cap(Bar)) + fmt.println("min:", min(Bar)) + fmt.println("max:", max(Bar)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Bar))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Bar)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Bar, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Bar, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Bar, 2))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Bar, i8)) + fmt.println("index of u16:", intrinsics.type_variant_index_of(Bar, u8)) + fmt.println("index of u8: ", intrinsics.type_variant_index_of(Bar, b8)) + fmt.println() + + Baz :: union #shared_nil { + []u8, // 1 + rawptr, // 2 + ^u8, // 3 + } + + fmt.println(typeid_of(Baz)) + fmt.println("size_of:", size_of(Baz)) + fmt.println("len:", len(Baz)) + fmt.println("cap:", cap(Baz)) + fmt.println("min:", min(Baz)) + fmt.println("max:", max(Baz)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Baz))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Baz)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Baz, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Baz, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Baz, 2))) + fmt.println("index of []u8: ", intrinsics.type_variant_index_of(Baz, []u8)) + fmt.println("index of rawptr:", intrinsics.type_variant_index_of(Baz, rawptr)) + fmt.println("index of ^u8: ", intrinsics.type_variant_index_of(Baz, ^u8)) + fmt.println() + + Mby :: Maybe(f32) + + fmt.println(typeid_of(Mby)) + fmt.println("size_of:", size_of(Mby)) + fmt.println("len:", len(Mby)) + fmt.println("cap:", cap(Mby)) + fmt.println("min:", min(Mby)) + fmt.println("max:", max(Mby)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Mby))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Mby)) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Mby, 0))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Mby, f32)) + fmt.println() + + // #unroll for i in 0 ..< intrinsics.type_proc_parameter_count(Proc) { + // fmt.println(intrinsics.type_proc_parameter_type(Proc, i)) + // } + + // arr: Packed_Union_Array(Foo) + // init(&arr) + + // append(&arr, f32(1.23)) + // append(&arr, f32(-1)) + // append(&arr, f32(-2)) + // append(&arr, f32(-3)) + // append(&arr, u8(0)) + // append(&arr, u8(255)) + // append(&arr, u8(255)) + + // fmt.println(get_data(arr, f32)) + // fmt.println(get_data(arr, u16)) + // fmt.println(get_data(arr, u8)) + + // pool: Packed_Union_Pool(Foo) + // packed_union_pool_init(&pool) + + // a := packed_union_pool_insert(&pool, f32(1.0)) + // packed_union_pool_insert(&pool, f32(3.0)) + // packed_union_pool_insert(&pool, u8(0)) + // packed_union_pool_remove(&pool, a) + // packed_union_pool_insert(&pool, f32(1.234)) + + // // prints 1.234 since it was overwritten + // fmt.println(a^) +} + + +// Packed_Union_Array_Variant :: struct { +// data: []u8, +// len: int, +// } + +// Packed_Union_Array :: struct($T: typeid) where intrinsics.type_is_union(T) { +// variants: [len(T)]Packed_Union_Array_Variant, +// allocator: runtime.Allocator, +// } + +// packed_union_array_init :: proc( +// a: ^$T/Packed_Union_Array($U), +// cap: int = 32, +// allocator := context.allocator, +// ) { +// a^ = { +// allocator = allocator, +// } + +// // RTTI hack since a loop cannot produce compile-time constant +// ti := reflect.type_info_base(type_info_of(U)).variant.(reflect.Type_Info_Union) +// for &v, i in a.variants { +// data, _ := mem.alloc_bytes_non_zeroed(cap * ti.variants[i].size) +// v = { +// data = data, +// len = 0, +// } +// } +// } + +// packed_union_array_append :: proc( +// a: ^$T/Packed_Union_Array($U), +// value: $V, +// ) where intrinsics.type_is_variant_of(U, V) { +// variants := &a.variants[intrinsics.type_variant_index_of(U, V)] + +// if variants.len >= len(variants.data) { +// // alloc more +// } + +// data := packed_union_array_get_data_buf(a^, V) +// data[variants.len / size_of(V)] = value +// variants.len += size_of(V) +// } + +// packed_union_array_set :: proc( +// a: $T/Packed_Union_Array($U), +// index: int, +// value: $V, +// ) where intrinsics.type_is_variant_of(U, V) { +// packed_union_array_get_data(a, V)[index] = value +// } + +// packed_union_array_get :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// index: int, +// ) -> V where intrinsics.type_is_variant_of(U, V) { +// return packed_union_array_get_data(a, V)[index] +// } + +// packed_union_array_get_data :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// ) -> []V where intrinsics.type_is_variant_of(U, V) { +// vars := a.variants[intrinsics.type_variant_index_of(U, V)] +// return slice.reinterpret([]V, vars.data)[:vars.len / size_of(V)] +// } + +// packed_union_array_get_data_buf :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// ) -> []V where intrinsics.type_is_variant_of(U, V) { +// return slice.reinterpret([]V, a.variants[intrinsics.type_variant_index_of(U, V)].data) +// } + +// // Basically like a pool with free list size buckets, but optimized for the specific union type. +// Packed_Union_Pool :: struct($T: typeid) where intrinsics.type_is_union(T) { +// // Should be a fast allocator like an arena. +// allocator: runtime.Allocator, +// free_lists: [len(T)]rawptr, +// } + +// Packed_Union_Pool_Item :: struct($T: typeid) { +// data: T, +// next_free: rawptr, +// } + +// packed_union_pool_init :: proc(p: ^$T/Packed_Union_Pool($U), allocator := context.allocator) { +// p^ = { +// allocator = allocator, +// } +// } + +// packed_union_pool_insert :: proc( +// p: ^$T/Packed_Union_Pool($U), +// val: $V, +// ) -> ( +// result: ^V, +// err: mem.Allocator_Error, +// ) #optional_allocator_error { +// ptr := cast(^Packed_Union_Pool_Item(V))p.free_lists[intrinsics.type_variant_index_of(U, V)] +// if ptr == nil { +// ptr = new(Packed_Union_Pool_Item(V), p.allocator) or_return +// } else { +// p.free_lists[intrinsics.type_variant_index_of(U, V)] = ptr.next_free +// } + +// ptr^ = { +// data = val, +// next_free = nil, +// } + +// return &ptr.data, nil +// } + +// packed_union_pool_remove :: proc(p: ^$T/Packed_Union_Pool($U), ptr: ^$V) { +// assert(ptr != nil) + +// item := cast(^Packed_Union_Pool_Item(V))ptr +// item.next_free = p.free_lists[intrinsics.type_variant_index_of(U, V)] +// p.free_lists[intrinsics.type_variant_index_of(U, V)] = item +// } From a573d076e4dbef0bb0fc8cd8479a5b9a0f5586f0 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:24:42 +0200 Subject: [PATCH 006/160] Delete test.odin --- test.odin | 272 ------------------------------------------------------ 1 file changed, 272 deletions(-) delete mode 100644 test.odin diff --git a/test.odin b/test.odin deleted file mode 100644 index 0930184ac..000000000 --- a/test.odin +++ /dev/null @@ -1,272 +0,0 @@ -package test - -import "core:fmt" -import "core:intrinsics" -import "core:mem" -import "core:reflect" -import "core:runtime" -import "core:slice" - -// TODO: extend for loops? - -get_tag :: proc(u: $T) -> int where intrinsics.type_is_union(T) { - u := u - return int( - (cast(^intrinsics.type_union_tag_type(T))(uintptr(&u) + - intrinsics.type_union_tag_offset(T)))^, - ) -} - -set_tag :: proc(u: ^$T, tag: int) where intrinsics.type_is_union(T) { - TAG :: intrinsics.type_union_tag_type(T) - (cast(^TAG)(uintptr(u) + intrinsics.type_union_tag_offset(T)))^ = TAG(tag) -} - -get_variant_index :: proc(u: $T) -> int where intrinsics.type_is_union(T) { - return min(T) + get_tag(u) -} - -main :: proc() { - Foo :: union { - f32, // 1 - u16, // 2 - u8, // 3 - } - - fmt.println(typeid_of(Foo)) - fmt.println("size_of:", size_of(Foo)) - fmt.println("len:", len(Foo)) - fmt.println("cap:", cap(Foo)) - fmt.println("min:", min(Foo)) - fmt.println("max:", max(Foo)) - fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Foo))) - fmt.println("tag offset:", intrinsics.type_union_tag_offset(Foo)) - fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Foo, 0))) - fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Foo, 1))) - fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Foo, 2))) - fmt.println("index of f32:", intrinsics.type_variant_index_of(Foo, f32)) - fmt.println("index of u16:", intrinsics.type_variant_index_of(Foo, u16)) - fmt.println("index of u8 :", intrinsics.type_variant_index_of(Foo, u8)) - // Goofy test of unsafe tag manipulation - foo: Foo = u16(255 + 255 << 8) - assert(get_tag(foo) == 2) - fmt.println(foo) - set_tag(&foo, 3) - assert(get_tag(foo) == 3) - fmt.println(foo) - fmt.println() - - Bar :: union #no_nil { - i8, // 0 - u8, // 1 - b8, // 2 - } - - fmt.println(typeid_of(Bar)) - fmt.println("size_of:", size_of(Bar)) - fmt.println("len:", len(Bar)) - fmt.println("cap:", cap(Bar)) - fmt.println("min:", min(Bar)) - fmt.println("max:", max(Bar)) - fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Bar))) - fmt.println("tag offset:", intrinsics.type_union_tag_offset(Bar)) - fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Bar, 0))) - fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Bar, 1))) - fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Bar, 2))) - fmt.println("index of f32:", intrinsics.type_variant_index_of(Bar, i8)) - fmt.println("index of u16:", intrinsics.type_variant_index_of(Bar, u8)) - fmt.println("index of u8: ", intrinsics.type_variant_index_of(Bar, b8)) - fmt.println() - - Baz :: union #shared_nil { - []u8, // 1 - rawptr, // 2 - ^u8, // 3 - } - - fmt.println(typeid_of(Baz)) - fmt.println("size_of:", size_of(Baz)) - fmt.println("len:", len(Baz)) - fmt.println("cap:", cap(Baz)) - fmt.println("min:", min(Baz)) - fmt.println("max:", max(Baz)) - fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Baz))) - fmt.println("tag offset:", intrinsics.type_union_tag_offset(Baz)) - fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Baz, 0))) - fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Baz, 1))) - fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Baz, 2))) - fmt.println("index of []u8: ", intrinsics.type_variant_index_of(Baz, []u8)) - fmt.println("index of rawptr:", intrinsics.type_variant_index_of(Baz, rawptr)) - fmt.println("index of ^u8: ", intrinsics.type_variant_index_of(Baz, ^u8)) - fmt.println() - - Mby :: Maybe(f32) - - fmt.println(typeid_of(Mby)) - fmt.println("size_of:", size_of(Mby)) - fmt.println("len:", len(Mby)) - fmt.println("cap:", cap(Mby)) - fmt.println("min:", min(Mby)) - fmt.println("max:", max(Mby)) - fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Mby))) - fmt.println("tag offset:", intrinsics.type_union_tag_offset(Mby)) - fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Mby, 0))) - fmt.println("index of f32:", intrinsics.type_variant_index_of(Mby, f32)) - fmt.println() - - // #unroll for i in 0 ..< intrinsics.type_proc_parameter_count(Proc) { - // fmt.println(intrinsics.type_proc_parameter_type(Proc, i)) - // } - - // arr: Packed_Union_Array(Foo) - // init(&arr) - - // append(&arr, f32(1.23)) - // append(&arr, f32(-1)) - // append(&arr, f32(-2)) - // append(&arr, f32(-3)) - // append(&arr, u8(0)) - // append(&arr, u8(255)) - // append(&arr, u8(255)) - - // fmt.println(get_data(arr, f32)) - // fmt.println(get_data(arr, u16)) - // fmt.println(get_data(arr, u8)) - - // pool: Packed_Union_Pool(Foo) - // packed_union_pool_init(&pool) - - // a := packed_union_pool_insert(&pool, f32(1.0)) - // packed_union_pool_insert(&pool, f32(3.0)) - // packed_union_pool_insert(&pool, u8(0)) - // packed_union_pool_remove(&pool, a) - // packed_union_pool_insert(&pool, f32(1.234)) - - // // prints 1.234 since it was overwritten - // fmt.println(a^) -} - - -// Packed_Union_Array_Variant :: struct { -// data: []u8, -// len: int, -// } - -// Packed_Union_Array :: struct($T: typeid) where intrinsics.type_is_union(T) { -// variants: [len(T)]Packed_Union_Array_Variant, -// allocator: runtime.Allocator, -// } - -// packed_union_array_init :: proc( -// a: ^$T/Packed_Union_Array($U), -// cap: int = 32, -// allocator := context.allocator, -// ) { -// a^ = { -// allocator = allocator, -// } - -// // RTTI hack since a loop cannot produce compile-time constant -// ti := reflect.type_info_base(type_info_of(U)).variant.(reflect.Type_Info_Union) -// for &v, i in a.variants { -// data, _ := mem.alloc_bytes_non_zeroed(cap * ti.variants[i].size) -// v = { -// data = data, -// len = 0, -// } -// } -// } - -// packed_union_array_append :: proc( -// a: ^$T/Packed_Union_Array($U), -// value: $V, -// ) where intrinsics.type_is_variant_of(U, V) { -// variants := &a.variants[intrinsics.type_variant_index_of(U, V)] - -// if variants.len >= len(variants.data) { -// // alloc more -// } - -// data := packed_union_array_get_data_buf(a^, V) -// data[variants.len / size_of(V)] = value -// variants.len += size_of(V) -// } - -// packed_union_array_set :: proc( -// a: $T/Packed_Union_Array($U), -// index: int, -// value: $V, -// ) where intrinsics.type_is_variant_of(U, V) { -// packed_union_array_get_data(a, V)[index] = value -// } - -// packed_union_array_get :: proc( -// a: $T/Packed_Union_Array($U), -// $V: typeid, -// index: int, -// ) -> V where intrinsics.type_is_variant_of(U, V) { -// return packed_union_array_get_data(a, V)[index] -// } - -// packed_union_array_get_data :: proc( -// a: $T/Packed_Union_Array($U), -// $V: typeid, -// ) -> []V where intrinsics.type_is_variant_of(U, V) { -// vars := a.variants[intrinsics.type_variant_index_of(U, V)] -// return slice.reinterpret([]V, vars.data)[:vars.len / size_of(V)] -// } - -// packed_union_array_get_data_buf :: proc( -// a: $T/Packed_Union_Array($U), -// $V: typeid, -// ) -> []V where intrinsics.type_is_variant_of(U, V) { -// return slice.reinterpret([]V, a.variants[intrinsics.type_variant_index_of(U, V)].data) -// } - -// // Basically like a pool with free list size buckets, but optimized for the specific union type. -// Packed_Union_Pool :: struct($T: typeid) where intrinsics.type_is_union(T) { -// // Should be a fast allocator like an arena. -// allocator: runtime.Allocator, -// free_lists: [len(T)]rawptr, -// } - -// Packed_Union_Pool_Item :: struct($T: typeid) { -// data: T, -// next_free: rawptr, -// } - -// packed_union_pool_init :: proc(p: ^$T/Packed_Union_Pool($U), allocator := context.allocator) { -// p^ = { -// allocator = allocator, -// } -// } - -// packed_union_pool_insert :: proc( -// p: ^$T/Packed_Union_Pool($U), -// val: $V, -// ) -> ( -// result: ^V, -// err: mem.Allocator_Error, -// ) #optional_allocator_error { -// ptr := cast(^Packed_Union_Pool_Item(V))p.free_lists[intrinsics.type_variant_index_of(U, V)] -// if ptr == nil { -// ptr = new(Packed_Union_Pool_Item(V), p.allocator) or_return -// } else { -// p.free_lists[intrinsics.type_variant_index_of(U, V)] = ptr.next_free -// } - -// ptr^ = { -// data = val, -// next_free = nil, -// } - -// return &ptr.data, nil -// } - -// packed_union_pool_remove :: proc(p: ^$T/Packed_Union_Pool($U), ptr: ^$V) { -// assert(ptr != nil) - -// item := cast(^Packed_Union_Pool_Item(V))ptr -// item.next_free = p.free_lists[intrinsics.type_variant_index_of(U, V)] -// p.free_lists[intrinsics.type_variant_index_of(U, V)] = item -// } From 160b23f991ff796b1d9a95ab793eabad9a2c33c6 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:23:26 +0200 Subject: [PATCH 007/160] Remove len,cap,min,max and implement type_union_base_tag_value, type_union_variant_count --- core/intrinsics/intrinsics.odin | 8 ++-- src/check_builtin.cpp | 79 +++++++++++++++++++++++---------- src/checker_builtin_procs.hpp | 14 +++--- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 62f3d1ad2..afa0efa36 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -164,9 +164,11 @@ type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- -type_union_tag_type :: proc($U: typeid) -> typeid where type_is_union(U) --- -type_union_tag_offset :: proc($U: typeid) -> int where type_is_union(U) --- -type_variant_type_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- +type_union_tag_type :: proc($T: typeid) -> typeid where type_is_union(T) --- +type_union_tag_offset :: proc($T: typeid) -> int where type_is_union(T) --- +type_union_base_tag_value :: proc($T: typeid) -> int where type_is_union(U) --- +type_union_variant_count :: proc($T: typeid) -> int where type_is_union(T) --- +type_variant_type_of :: proc($T: typeid, $index: int) -> typeid where type_is_union(T) --- type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5907b30e3..03850ce50 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1780,11 +1780,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; - } else if (is_type_union(op_type)) { - Type *u = base_type(op_type); - mode = Addressing_Constant; - value = exact_value_i64(u->Union.variants.count); - type = t_untyped_integer; } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; @@ -2597,7 +2592,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2662,14 +2657,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.min_value; return true; - } else if (is_type_union(type)) { - Type *bt = base_type(type); - GB_ASSERT(bt->kind == Type_Union); - operand->mode = Addressing_Constant; - operand->type = t_untyped_integer; - i64 min_tag = bt->Union.kind == UnionType_no_nil ? 0 : 1; - operand->value = exact_value_i64(min_tag); - return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'min', got %s", type_str); @@ -2774,7 +2761,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2844,14 +2831,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.max_value; return true; - } else if (is_type_union(type)) { - Type *bt = base_type(type); - GB_ASSERT(bt->kind == Type_Union); - operand->mode = Addressing_Constant; - operand->type = t_untyped_integer; - i64 max_tag = (bt->Union.kind == UnionType_no_nil ? 0 : 1) + bt->Union.variants.count - 1; - operand->value = exact_value_i64(max_tag); - return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'max', got %s", type_str); @@ -5163,7 +5142,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = union_tag_type(u); } break; - + case BuiltinProc_type_union_tag_offset: { if (operand->mode != Addressing_Type) { @@ -5196,6 +5175,58 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_union_base_tag_value: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(u->Union.kind == UnionType_no_nil ? 0 : 1); + } break; + + case BuiltinProc_type_union_variant_count: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(u->Union.variants.count); + } break; + case BuiltinProc_type_variant_type_of: { if (operand->mode != Addressing_Type) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 35ca9c51e..3bab16293 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -262,6 +262,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_variant_of, BuiltinProc_type_union_tag_type, BuiltinProc_type_union_tag_offset, + BuiltinProc_type_union_base_tag_value, + BuiltinProc_type_union_variant_count, BuiltinProc_type_variant_type_of, BuiltinProc_type_variant_index_of, @@ -561,11 +563,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_base_tag_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_variant_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From 2b2abc6b9f03d32ba3f9dc9f1c260a724f6e4701 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Fri, 27 Oct 2023 19:12:25 +0200 Subject: [PATCH 008/160] Dbghelp --- core/sys/windows/dbghelp.odin | 250 ++++++++++++++++++++++++++++++++++ core/sys/windows/types.odin | 2 + 2 files changed, 252 insertions(+) create mode 100644 core/sys/windows/dbghelp.odin diff --git a/core/sys/windows/dbghelp.odin b/core/sys/windows/dbghelp.odin new file mode 100644 index 000000000..baddbc58e --- /dev/null +++ b/core/sys/windows/dbghelp.odin @@ -0,0 +1,250 @@ +// +build windows +package sys_windows + +foreign import "system:Dbghelp.lib" + +RVA :: DWORD + +MINIDUMP_LOCATION_DESCRIPTOR :: struct { + DataSize: ULONG32, + Rva: RVA, +} + +MINIDUMP_DIRECTORY :: struct { + StreamType: ULONG32, + Location: MINIDUMP_LOCATION_DESCRIPTOR, +} + +MINIDUMP_EXCEPTION_INFORMATION :: struct { + ThreadId: DWORD, + ExceptionPointers: ^EXCEPTION_POINTERS, + ClientPointers: BOOL, +} + +MINIDUMP_MEMORY_INFO :: struct { + BaseAddress: ULONG64, + AllocationBase: ULONG64, + AllocationProtect: ULONG32, + __alignment1: ULONG32, + RegionSize: ULONG64, + State: ULONG32, + Protect: ULONG32, + Type: ULONG32, + __alignment2: ULONG32, +} + +MINIDUMP_USER_STREAM :: struct { + Type: ULONG32, + BufferSize: ULONG, + Buffer: PVOID, +} + +MINIDUMP_USER_STREAM_INFORMATION :: struct { + UserStreamCount: ULONG, + UserStreamArray: ^MINIDUMP_USER_STREAM, +} + +MINIDUMP_CALLBACK_ROUTINE :: #type proc "stdcall" ( + CallbackParam: PVOID, + CallbackInput: ^MINIDUMP_CALLBACK_INPUT, + CallbackOutpu: ^MINIDUMP_CALLBACK_OUTPUT, +) -> BOOL + +MINIDUMP_CALLBACK_INFORMATION :: struct { + CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE, + CallbackParam: PVOID, +} + +MINIDUMP_CALLBACK_INPUT :: struct { + ProcessId: ULONG, + ProcessHandle: HANDLE, + CallbackType: ULONG, + using _: struct #raw_union { + Status: HRESULT, + Thread: MINIDUMP_THREAD_CALLBACK, + ThreadEx: MINIDUMP_THREAD_EX_CALLBACK, + Module: MINIDUMP_MODULE_CALLBACK, + IncludeThread: MINIDUMP_INCLUDE_THREAD_CALLBACK, + IncludeModule: MINIDUMP_INCLUDE_MODULE_CALLBACK, + Io: MINIDUMP_IO_CALLBACK, + ReadMemoryFailure: MINIDUMP_READ_MEMORY_FAILURE_CALLBACK, + SecondaryFlags: ULONG, + VmQuery: MINIDUMP_VM_QUERY_CALLBACK, + VmPreRead: MINIDUMP_VM_PRE_READ_CALLBACK, + VmPostRead: MINIDUMP_VM_POST_READ_CALLBACK, + }, +} + +_MINIDUMP_ARM64_PAD :: ULONG when ODIN_ARCH == .arm64 else struct {} + +MINIDUMP_THREAD_CALLBACK :: struct { + ThreadId: ULONG, + ThreadHandle: HANDLE, + Pad: _MINIDUMP_ARM64_PAD, + Context: CONTEXT, + SizeOfContext: ULONG, + StackBase: ULONG64, + StackEnd: ULONG64, +} + +MINIDUMP_THREAD_EX_CALLBACK :: struct { + ThreadId: ULONG, + ThreadHandle: HANDLE, + Pad: _MINIDUMP_ARM64_PAD, + Context: CONTEXT, + SizeOfContext: ULONG, + StackBase: ULONG64, + StackEnd: ULONG64, + BackingStoreBase: ULONG64, + BackingStoreEnd: ULONG64, +} + +MINIDUMP_INCLUDE_THREAD_CALLBACK :: struct { + ThreadId: ULONG, +} + +// NOTE(jakubtomsu): From verrsrc.h +VS_FIXEDFILEINFO :: struct { + dwSignature: DWORD, /* e.g. 0xfeef04bd */ + dwStrucVersion: DWORD, /* e.g. 0x00000042 = "0.42" */ + dwFileVersionMS: DWORD, /* e.g. 0x00030075 = "3.75" */ + dwFileVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */ + dwProductVersionMS: DWORD, /* e.g. 0x00030010 = "3.10" */ + dwProductVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */ + dwFileFlagsMask: DWORD, /* = 0x3F for version "0.42" */ + dwFileFlags: DWORD, /* e.g. VFF_DEBUG | VFF_PRERELEASE */ + dwFileOS: DWORD, /* e.g. VOS_DOS_WINDOWS16 */ + dwFileType: DWORD, /* e.g. VFT_DRIVER */ + dwFileSubtype: DWORD, /* e.g. VFT2_DRV_KEYBOARD */ + dwFileDateMS: DWORD, /* e.g. 0 */ + dwFileDateLS: DWORD, /* e.g. 0 */ +} + +MINIDUMP_MODULE_CALLBACK :: struct { + FullPath: ^WCHAR, + BaseOfImage: ULONG64, + SizeOfImage: ULONG, + CheckSum: ULONG, + TimeDateStamp: ULONG, + VersionInfo: VS_FIXEDFILEINFO, + CvRecord: PVOID, + SizeOfCvRecord: ULONG, + MiscRecord: PVOID, + SizeOfMiscRecord: ULONG, +} + +MINIDUMP_INCLUDE_MODULE_CALLBACK :: struct { + BaseOfImage: u64, +} + +MINIDUMP_IO_CALLBACK :: struct { + Handle: HANDLE, + Offset: ULONG64, + Buffer: PVOID, + BufferBytes: ULONG, +} + +MINIDUMP_READ_MEMORY_FAILURE_CALLBACK :: struct { + Offset: ULONG64, + Bytes: ULONG, + FailureStatus: HRESULT, +} + +MINIDUMP_VM_QUERY_CALLBACK :: struct { + Offset: ULONG64, +} + +MINIDUMP_VM_PRE_READ_CALLBACK :: struct { + Offset: ULONG64, + Buffer: PVOID, + Size: ULONG, +} + +MINIDUMP_VM_POST_READ_CALLBACK :: struct { + Offset: ULONG64, + Buffer: PVOID, + Size: ULONG, + Completed: ULONG, + Status: HRESULT, +} + +MINIDUMP_CALLBACK_OUTPUT :: struct { + using _: struct #raw_union { + ModuleWriteFlags: ULONG, + ThreadWriteFlags: ULONG, + SecondaryFlags: ULONG, + using _: struct { + MemoryBase: ULONG64, + MemorySize: ULONG, + }, + using _: struct { + CheckCancel: BOOL, + Cancel: BOOL, + }, + Handle: HANDLE, + using _: struct { + VmRegion: MINIDUMP_MEMORY_INFO, + Continue: BOOL, + }, + using _: struct { + VmQueryStatus: HRESULT, + VmQueryResult: MINIDUMP_MEMORY_INFO, + }, + using _: struct { + VmReadStatus: HRESULT, + VmReadBytesCompleted: ULONG, + }, + Status: HRESULT, + }, +} + +MINIDUMP_TYPE :: enum u32 { + Normal = 0x00000000, + WithDataSegs = 0x00000001, + WithFullMemory = 0x00000002, + WithHandleData = 0x00000004, + FilterMemory = 0x00000008, + ScanMemory = 0x00000010, + WithUnloadedModules = 0x00000020, + WithIndirectlyReferencedMemory = 0x00000040, + FilterModulePaths = 0x00000080, + WithProcessThreadData = 0x00000100, + WithPrivateReadWriteMemory = 0x00000200, + WithoutOptionalData = 0x00000400, + WithFullMemoryInfo = 0x00000800, + WithThreadInfo = 0x00001000, + WithCodeSegs = 0x00002000, + WithoutAuxiliaryState = 0x00004000, + WithFullAuxiliaryState = 0x00008000, + WithPrivateWriteCopyMemory = 0x00010000, + IgnoreInaccessibleMemory = 0x00020000, + WithTokenInformation = 0x00040000, + WithModuleHeaders = 0x00080000, + FilterTriage = 0x00100000, + WithAvxXStateContext = 0x00200000, + WithIptTrace = 0x00400000, + ScanInaccessiblePartialPages = 0x00800000, + FilterWriteCombinedMemory = 0x01000000, + ValidTypeFlags = 0x01ffffff, +} + +@(default_calling_convention = "stdcall") +foreign Dbghelp { + MiniDumpWriteDump :: proc( + hProcess: HANDLE, + ProcessId: DWORD, + hFile: HANDLE, + DumpType: MINIDUMP_TYPE, + ExceptionParam: ^MINIDUMP_EXCEPTION_INFORMATION, + UserStreamParam: ^MINIDUMP_USER_STREAM_INFORMATION, + CallbackPara: ^MINIDUMP_CALLBACK_INFORMATION, + ) -> BOOL --- + + MiniDumpReadDumpStream :: proc( + BaseOfDump: PVOID, + StreamNumber: ULONG, + Dir: ^^MINIDUMP_DIRECTORY, + StreamPointer: ^PVOID, + StreamSize: ^ULONG, + ) -> BOOL --- +} diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index d5377eb2f..f8dac242a 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -86,6 +86,8 @@ INT16 :: i16 INT32 :: i32 INT64 :: i64 +ULONG32 :: u32 +LONG32 :: i32 ULONG64 :: u64 LONG64 :: i64 From 7a16618ec601e2a1b67ab5d6f41b3aed96cba732 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Fri, 27 Oct 2023 19:12:49 +0200 Subject: [PATCH 009/160] SHGetKnownFolderPath etc. --- core/sys/windows/known_folders.odin | 145 ++++++++++++++++++++++++++++ core/sys/windows/shell32.odin | 41 +++++++- 2 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 core/sys/windows/known_folders.odin diff --git a/core/sys/windows/known_folders.odin b/core/sys/windows/known_folders.odin new file mode 100644 index 000000000..43e132e17 --- /dev/null +++ b/core/sys/windows/known_folders.odin @@ -0,0 +1,145 @@ +// +build windows +package sys_windows + +FOLDERID_NetworkFolder: GUID : {0xD20BEEC4, 0x5CA8, 0x4905, {0xAE, 0x3B, 0xBF, 0x25, 0x1E, 0xA0, 0x9B, 0x53}} +FOLDERID_ComputerFolder: GUID : {0x0AC0837C, 0xBBF8, 0x452A, {0x85, 0x0D, 0x79, 0xD0, 0x8E, 0x66, 0x7C, 0xA7}} +FOLDERID_InternetFolder: GUID : {0x4D9F7874, 0x4E0C, 0x4904, {0x96, 0x7B, 0x40, 0xB0, 0xD2, 0x0C, 0x3E, 0x4B}} +FOLDERID_ControlPanelFolder: GUID : {0x82A74AEB, 0xAEB4, 0x465C, {0xA0, 0x14, 0xD0, 0x97, 0xEE, 0x34, 0x6D, 0x63}} +FOLDERID_PrintersFolder: GUID : {0x76FC4E2D, 0xD6AD, 0x4519, {0xA6, 0x63, 0x37, 0xBD, 0x56, 0x06, 0x81, 0x85}} +FOLDERID_SyncManagerFolder: GUID : {0x43668BF8, 0xC14E, 0x49B2, {0x97, 0xC9, 0x74, 0x77, 0x84, 0xD7, 0x84, 0xB7}} +FOLDERID_SyncSetupFolder: GUID : {0xf214138 , 0xb1d3, 0x4a90, {0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a}} +FOLDERID_ConflictFolder: GUID : {0x4bfefb45, 0x347d, 0x4006, {0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92}} +FOLDERID_SyncResultsFolder: GUID : {0x289a9a43, 0xbe44, 0x4057, {0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9}} +FOLDERID_RecycleBinFolder: GUID : {0xB7534046, 0x3ECB, 0x4C18, {0xBE, 0x4E, 0x64, 0xCD, 0x4C, 0xB7, 0xD6, 0xAC}} +FOLDERID_ConnectionsFolder: GUID : {0x6F0CD92B, 0x2E97, 0x45D1, {0x88, 0xFF, 0xB0, 0xD1, 0x86, 0xB8, 0xDE, 0xDD}} +FOLDERID_Fonts: GUID : {0xFD228CB7, 0xAE11, 0x4AE3, {0x86, 0x4C, 0x16, 0xF3, 0x91, 0x0A, 0xB8, 0xFE}} +FOLDERID_Desktop: GUID : {0xB4BFCC3A, 0xDB2C, 0x424C, {0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41}} +FOLDERID_Startup: GUID : {0xB97D20BB, 0xF46A, 0x4C97, {0xBA, 0x10, 0x5E, 0x36, 0x08, 0x43, 0x08, 0x54}} +FOLDERID_Programs: GUID : {0xA77F5D77, 0x2E2B, 0x44C3, {0xA6, 0xA2, 0xAB, 0xA6, 0x01, 0x05, 0x4A, 0x51}} +FOLDERID_StartMenu: GUID : {0x625B53C3, 0xAB48, 0x4EC1, {0xBA, 0x1F, 0xA1, 0xEF, 0x41, 0x46, 0xFC, 0x19}} +FOLDERID_Recent: GUID : {0xAE50C081, 0xEBD2, 0x438A, {0x86, 0x55, 0x8A, 0x09, 0x2E, 0x34, 0x98, 0x7A}} +FOLDERID_SendTo: GUID : {0x8983036C, 0x27C0, 0x404B, {0x8F, 0x08, 0x10, 0x2D, 0x10, 0xDC, 0xFD, 0x74}} +FOLDERID_Documents: GUID : {0xFDD39AD0, 0x238F, 0x46AF, {0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7}} +FOLDERID_Favorites: GUID : {0x1777F761, 0x68AD, 0x4D8A, {0x87, 0xBD, 0x30, 0xB7, 0x59, 0xFA, 0x33, 0xDD}} +FOLDERID_NetHood: GUID : {0xC5ABBF53, 0xE17F, 0x4121, {0x89, 0x00, 0x86, 0x62, 0x6F, 0xC2, 0xC9, 0x73}} +FOLDERID_PrintHood: GUID : {0x9274BD8D, 0xCFD1, 0x41C3, {0xB3, 0x5E, 0xB1, 0x3F, 0x55, 0xA7, 0x58, 0xF4}} +FOLDERID_Templates: GUID : {0xA63293E8, 0x664E, 0x48DB, {0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7}} +FOLDERID_CommonStartup: GUID : {0x82A5EA35, 0xD9CD, 0x47C5, {0x96, 0x29, 0xE1, 0x5D, 0x2F, 0x71, 0x4E, 0x6E}} +FOLDERID_CommonPrograms: GUID : {0x0139D44E, 0x6AFE, 0x49F2, {0x86, 0x90, 0x3D, 0xAF, 0xCA, 0xE6, 0xFF, 0xB8}} +FOLDERID_CommonStartMenu: GUID : {0xA4115719, 0xD62E, 0x491D, {0xAA, 0x7C, 0xE7, 0x4B, 0x8B, 0xE3, 0xB0, 0x67}} +FOLDERID_PublicDesktop: GUID : {0xC4AA340D, 0xF20F, 0x4863, {0xAF, 0xEF, 0xF8, 0x7E, 0xF2, 0xE6, 0xBA, 0x25}} +FOLDERID_ProgramData: GUID : {0x62AB5D82, 0xFDC1, 0x4DC3, {0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97}} +FOLDERID_CommonTemplates: GUID : {0xB94237E7, 0x57AC, 0x4347, {0x91, 0x51, 0xB0, 0x8C, 0x6C, 0x32, 0xD1, 0xF7}} +FOLDERID_PublicDocuments: GUID : {0xED4824AF, 0xDCE4, 0x45A8, {0x81, 0xE2, 0xFC, 0x79, 0x65, 0x08, 0x36, 0x34}} +FOLDERID_RoamingAppData: GUID : {0x3EB685DB, 0x65F9, 0x4CF6, {0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D}} +FOLDERID_LocalAppData: GUID : {0xF1B32785, 0x6FBA, 0x4FCF, {0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91}} +FOLDERID_LocalAppDataLow: GUID : {0xA520A1A4, 0x1780, 0x4FF6, {0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16}} +FOLDERID_InternetCache: GUID : {0x352481E8, 0x33BE, 0x4251, {0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D}} +FOLDERID_Cookies: GUID : {0x2B0F765D, 0xC0E9, 0x4171, {0x90, 0x8E, 0x08, 0xA6, 0x11, 0xB8, 0x4F, 0xF6}} +FOLDERID_History: GUID : {0xD9DC8A3B, 0xB784, 0x432E, {0xA7, 0x81, 0x5A, 0x11, 0x30, 0xA7, 0x59, 0x63}} +FOLDERID_System: GUID : {0x1AC14E77, 0x02E7, 0x4E5D, {0xB7, 0x44, 0x2E, 0xB1, 0xAE, 0x51, 0x98, 0xB7}} +FOLDERID_SystemX86: GUID : {0xD65231B0, 0xB2F1, 0x4857, {0xA4, 0xCE, 0xA8, 0xE7, 0xC6, 0xEA, 0x7D, 0x27}} +FOLDERID_Windows: GUID : {0xF38BF404, 0x1D43, 0x42F2, {0x93, 0x05, 0x67, 0xDE, 0x0B, 0x28, 0xFC, 0x23}} +FOLDERID_Profile: GUID : {0x5E6C858F, 0x0E22, 0x4760, {0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73}} +FOLDERID_Pictures: GUID : {0x33E28130, 0x4E1E, 0x4676, {0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB}} +FOLDERID_ProgramFilesX86: GUID : {0x7C5A40EF, 0xA0FB, 0x4BFC, {0x87, 0x4A, 0xC0, 0xF2, 0xE0, 0xB9, 0xFA, 0x8E}} +FOLDERID_ProgramFilesCommonX86: GUID : {0xDE974D24, 0xD9C6, 0x4D3E, {0xBF, 0x91, 0xF4, 0x45, 0x51, 0x20, 0xB9, 0x17}} +FOLDERID_ProgramFilesX64: GUID : {0x6d809377, 0x6af0, 0x444b, {0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e}} +FOLDERID_ProgramFilesCommonX64: GUID : {0x6365d5a7, 0xf0d , 0x45e5, {0x87, 0xf6, 0xd, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d }} +FOLDERID_ProgramFiles: GUID : {0x905e63b6, 0xc1bf, 0x494e, {0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a}} +FOLDERID_ProgramFilesCommon: GUID : {0xF7F1ED05, 0x9F6D, 0x47A2, {0xAA, 0xAE, 0x29, 0xD3, 0x17, 0xC6, 0xF0, 0x66}} +FOLDERID_UserProgramFiles: GUID : {0x5cd7aee2, 0x2219, 0x4a67, {0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb}} +FOLDERID_UserProgramFilesCommon: GUID : {0xbcbd3057, 0xca5c, 0x4622, {0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16}} +FOLDERID_AdminTools: GUID : {0x724EF170, 0xA42D, 0x4FEF, {0x9F, 0x26, 0xB6, 0x0E, 0x84, 0x6F, 0xBA, 0x4F}} +FOLDERID_CommonAdminTools: GUID : {0xD0384E7D, 0xBAC3, 0x4797, {0x8F, 0x14, 0xCB, 0xA2, 0x29, 0xB3, 0x92, 0xB5}} +FOLDERID_Music: GUID : {0x4BD8D571, 0x6D19, 0x48D3, {0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43}} +FOLDERID_Videos: GUID : {0x18989B1D, 0x99B5, 0x455B, {0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC}} +FOLDERID_Ringtones: GUID : {0xC870044B, 0xF49E, 0x4126, {0xA9, 0xC3, 0xB5, 0x2A, 0x1F, 0xF4, 0x11, 0xE8}} +FOLDERID_PublicPictures: GUID : {0xB6EBFB86, 0x6907, 0x413C, {0x9A, 0xF7, 0x4F, 0xC2, 0xAB, 0xF0, 0x7C, 0xC5}} +FOLDERID_PublicMusic: GUID : {0x3214FAB5, 0x9757, 0x4298, {0xBB, 0x61, 0x92, 0xA9, 0xDE, 0xAA, 0x44, 0xFF}} +FOLDERID_PublicVideos: GUID : {0x2400183A, 0x6185, 0x49FB, {0xA2, 0xD8, 0x4A, 0x39, 0x2A, 0x60, 0x2B, 0xA3}} +FOLDERID_PublicRingtones: GUID : {0xE555AB60, 0x153B, 0x4D17, {0x9F, 0x04, 0xA5, 0xFE, 0x99, 0xFC, 0x15, 0xEC}} +FOLDERID_ResourceDir: GUID : {0x8AD10C31, 0x2ADB, 0x4296, {0xA8, 0xF7, 0xE4, 0x70, 0x12, 0x32, 0xC9, 0x72}} +FOLDERID_LocalizedResourcesDir: GUID : {0x2A00375E, 0x224C, 0x49DE, {0xB8, 0xD1, 0x44, 0x0D, 0xF7, 0xEF, 0x3D, 0xDC}} +FOLDERID_CommonOEMLinks: GUID : {0xC1BAE2D0, 0x10DF, 0x4334, {0xBE, 0xDD, 0x7A, 0xA2, 0x0B, 0x22, 0x7A, 0x9D}} +FOLDERID_CDBurning: GUID : {0x9E52AB10, 0xF80D, 0x49DF, {0xAC, 0xB8, 0x43, 0x30, 0xF5, 0x68, 0x78, 0x55}} +FOLDERID_UserProfiles: GUID : {0x0762D272, 0xC50A, 0x4BB0, {0xA3, 0x82, 0x69, 0x7D, 0xCD, 0x72, 0x9B, 0x80}} +FOLDERID_Playlists: GUID : {0xDE92C1C7, 0x837F, 0x4F69, {0xA3, 0xBB, 0x86, 0xE6, 0x31, 0x20, 0x4A, 0x23}} +FOLDERID_SamplePlaylists: GUID : {0x15CA69B3, 0x30EE, 0x49C1, {0xAC, 0xE1, 0x6B, 0x5E, 0xC3, 0x72, 0xAF, 0xB5}} +FOLDERID_SampleMusic: GUID : {0xB250C668, 0xF57D, 0x4EE1, {0xA6, 0x3C, 0x29, 0x0E, 0xE7, 0xD1, 0xAA, 0x1F}} +FOLDERID_SamplePictures: GUID : {0xC4900540, 0x2379, 0x4C75, {0x84, 0x4B, 0x64, 0xE6, 0xFA, 0xF8, 0x71, 0x6B}} +FOLDERID_SampleVideos: GUID : {0x859EAD94, 0x2E85, 0x48AD, {0xA7, 0x1A, 0x09, 0x69, 0xCB, 0x56, 0xA6, 0xCD}} +FOLDERID_PhotoAlbums: GUID : {0x69D2CF90, 0xFC33, 0x4FB7, {0x9A, 0x0C, 0xEB, 0xB0, 0xF0, 0xFC, 0xB4, 0x3C}} +FOLDERID_Public: GUID : {0xDFDF76A2, 0xC82A, 0x4D63, {0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85}} +FOLDERID_ChangeRemovePrograms: GUID : {0xdf7266ac, 0x9274, 0x4867, {0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d}} +FOLDERID_AppUpdates: GUID : {0xa305ce99, 0xf527, 0x492b, {0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4}} +FOLDERID_AddNewPrograms: GUID : {0xde61d971, 0x5ebc, 0x4f02, {0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04}} +FOLDERID_Downloads: GUID : {0x374de290, 0x123f, 0x4565, {0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}} +FOLDERID_PublicDownloads: GUID : {0x3d644c9b, 0x1fb8, 0x4f30, {0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0}} +FOLDERID_SavedSearches: GUID : {0x7d1d3a04, 0xdebb, 0x4115, {0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda}} +FOLDERID_QuickLaunch: GUID : {0x52a4f021, 0x7b75, 0x48a9, {0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f}} +FOLDERID_Contacts: GUID : {0x56784854, 0xc6cb, 0x462b, {0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82}} +FOLDERID_SidebarParts: GUID : {0xa75d362e, 0x50fc, 0x4fb7, {0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93}} +FOLDERID_SidebarDefaultParts: GUID : {0x7b396e54, 0x9ec5, 0x4300, {0xbe, 0xa , 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26}} +FOLDERID_PublicGameTasks: GUID : {0xdebf2536, 0xe1a8, 0x4c59, {0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea}} +FOLDERID_GameTasks: GUID : {0x54fae61 , 0x4dd8, 0x4787, {0x80, 0xb6, 0x9 , 0x2 , 0x20, 0xc4, 0xb7, 0x0 }} +FOLDERID_SavedGames: GUID : {0x4c5c32ff, 0xbb9d, 0x43b0, {0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}} +FOLDERID_Games: GUID : {0xcac52c1a, 0xb53d, 0x4edc, {0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34}} +FOLDERID_SEARCH_MAPI: GUID : {0x98ec0e18, 0x2098, 0x4d44, {0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81}} +FOLDERID_SEARCH_CSC: GUID : {0xee32e446, 0x31ca, 0x4aba, {0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e}} +FOLDERID_Links: GUID : {0xbfb9d5e0, 0xc6a9, 0x404c, {0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68}} +FOLDERID_UsersFiles: GUID : {0xf3ce0f7c, 0x4901, 0x4acc, {0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f}} +FOLDERID_UsersLibraries: GUID : {0xa302545d, 0xdeff, 0x464b, {0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b}} +FOLDERID_SearchHome: GUID : {0x190337d1, 0xb8ca, 0x4121, {0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a}} +FOLDERID_OriginalImages: GUID : {0x2C36C0AA, 0x5812, 0x4b87, {0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39}} +FOLDERID_DocumentsLibrary: GUID : {0x7b0db17d, 0x9cd2, 0x4a93, {0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c}} +FOLDERID_MusicLibrary: GUID : {0x2112ab0a, 0xc86a, 0x4ffe, {0xa3, 0x68, 0xd , 0xe9, 0x6e, 0x47, 0x1 , 0x2e}} +FOLDERID_PicturesLibrary: GUID : {0xa990ae9f, 0xa03b, 0x4e80, {0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x4 }} +FOLDERID_VideosLibrary: GUID : {0x491e922f, 0x5643, 0x4af4, {0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74}} +FOLDERID_RecordedTVLibrary: GUID : {0x1a6fdba2, 0xf42d, 0x4358, {0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5}} +FOLDERID_HomeGroup: GUID : {0x52528a6b, 0xb9e3, 0x4add, {0xb6, 0xd , 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d}} +FOLDERID_HomeGroupCurrentUser: GUID : {0x9b74b6a3, 0xdfd , 0x4f11, {0x9e, 0x78, 0x5f, 0x78, 0x0 , 0xf2, 0xe7, 0x72}} +FOLDERID_DeviceMetadataStore: GUID : {0x5ce4a5e9, 0xe4eb, 0x479d, {0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55}} +FOLDERID_Libraries: GUID : {0x1b3ea5dc, 0xb587, 0x4786, {0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae}} +FOLDERID_PublicLibraries: GUID : {0x48daf80b, 0xe6cf, 0x4f4e, {0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84}} +FOLDERID_UserPinned: GUID : {0x9e3995ab, 0x1f9c, 0x4f13, {0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74}} +FOLDERID_ImplicitAppShortcuts: GUID : {0xbcb5256f, 0x79f6, 0x4cee, {0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x2 , 0xfd, 0x46}} +FOLDERID_AccountPictures: GUID : {0x008ca0b1, 0x55b4, 0x4c56, {0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe}} +FOLDERID_PublicUserTiles: GUID : {0x0482af6c, 0x08f1, 0x4c34, {0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17}} +FOLDERID_AppsFolder: GUID : {0x1e87508d, 0x89c2, 0x42f0, {0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}} +FOLDERID_StartMenuAllPrograms: GUID : {0xf26305ef, 0x6948, 0x40b9, {0xb2, 0x55, 0x81, 0x45, 0x3d, 0x9 , 0xc7, 0x85}} +FOLDERID_CommonStartMenuPlaces: GUID : {0xa440879f, 0x87a0, 0x4f7d, {0xb7, 0x0 , 0x2 , 0x7 , 0xb9, 0x66, 0x19, 0x4a}} +FOLDERID_ApplicationShortcuts: GUID : {0xa3918781, 0xe5f2, 0x4890, {0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c}} +FOLDERID_RoamingTiles: GUID : {0xbcfc5a , 0xed94, 0x4e48, {0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90}} +FOLDERID_RoamedTileImages: GUID : {0xaaa8d5a5, 0xf1d6, 0x4259, {0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e}} +FOLDERID_Screenshots: GUID : {0xb7bede81, 0xdf94, 0x4682, {0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f}} +FOLDERID_CameraRoll: GUID : {0xab5fb87b, 0x7ce2, 0x4f83, {0x91, 0x5d, 0x55, 0x8 , 0x46, 0xc9, 0x53, 0x7b}} +FOLDERID_SkyDrive: GUID : {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}} +FOLDERID_OneDrive: GUID : {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}} +FOLDERID_SkyDriveDocuments: GUID : {0x24d89e24, 0x2f19, 0x4534, {0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe}} +FOLDERID_SkyDrivePictures: GUID : {0x339719b5, 0x8c47, 0x4894, {0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6}} +FOLDERID_SkyDriveMusic: GUID : {0xc3f2459e, 0x80d6, 0x45dc, {0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30}} +FOLDERID_SkyDriveCameraRoll: GUID : {0x767e6811, 0x49cb, 0x4273, {0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b}} +FOLDERID_SearchHistory: GUID : {0x0d4c3db6, 0x03a3, 0x462f, {0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4}} +FOLDERID_SearchTemplates: GUID : {0x7e636bfe, 0xdfa9, 0x4d5e, {0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9}} +FOLDERID_CameraRollLibrary: GUID : {0x2b20df75, 0x1eda, 0x4039, {0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7}} +FOLDERID_SavedPictures: GUID : {0x3b193882, 0xd3ad, 0x4eab, {0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f}} +FOLDERID_SavedPicturesLibrary: GUID : {0xe25b5812, 0xbe88, 0x4bd9, {0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3}} +FOLDERID_RetailDemo: GUID : {0x12d4c69e, 0x24ad, 0x4923, {0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67}} +FOLDERID_Device: GUID : {0x1C2AC1DC, 0x4358, 0x4B6C, {0x97, 0x33, 0xAF, 0x21, 0x15, 0x65, 0x76, 0xF0}} +FOLDERID_DevelopmentFiles: GUID : {0xdbe8e08e, 0x3053, 0x4bbc, {0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59}} +FOLDERID_Objects3D: GUID : {0x31c0dd25, 0x9439, 0x4f12, {0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22}} +FOLDERID_AppCaptures: GUID : {0xedc0fe71, 0x98d8, 0x4f4a, {0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65}} +FOLDERID_LocalDocuments: GUID : {0xf42ee2d3, 0x909f, 0x4907, {0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56}} +FOLDERID_LocalPictures: GUID : {0x0ddd015d, 0xb06c, 0x45d5, {0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39}} +FOLDERID_LocalVideos: GUID : {0x35286a68, 0x3c57, 0x41a1, {0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95}} +FOLDERID_LocalMusic: GUID : {0xa0c69a99, 0x21c8, 0x4671, {0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d}} +FOLDERID_LocalDownloads: GUID : {0x7d83ee9b, 0x2244, 0x4e70, {0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4}} +FOLDERID_RecordedCalls: GUID : {0x2f8b40c2, 0x83ed, 0x48ee, {0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a}} +FOLDERID_AllAppMods: GUID : {0x7ad67899, 0x66af, 0x43ba, {0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96}} +FOLDERID_CurrentAppMods: GUID : {0x3db40b20, 0x2a30, 0x4dbe, {0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99}} +FOLDERID_AppDataDesktop: GUID : {0xb2c5e279, 0x7add, 0x439f, {0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72}} +FOLDERID_AppDataDocuments: GUID : {0x7be16610, 0x1f7f, 0x44ac, {0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1}} +FOLDERID_AppDataFavorites: GUID : {0x7cfbefbc, 0xde1f, 0x45aa, {0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9}} +FOLDERID_AppDataProgramData: GUID : {0x559d40a3, 0xa036, 0x40fa, {0xaf, 0x61, 0x84, 0xcb, 0x43, 0xa , 0x4d, 0x34}} +FOLDERID_LocalStorage: GUID : {0xB3EB08D3, 0xA1F3, 0x496B, {0x86, 0x5A, 0x42, 0xB5, 0x36, 0xCD, 0xA0, 0xEC}} diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin index 0a6f90a44..f6aaf2c95 100644 --- a/core/sys/windows/shell32.odin +++ b/core/sys/windows/shell32.odin @@ -22,9 +22,13 @@ foreign shell32 { ) -> c_int --- SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int --- SHGetFolderPathW :: proc(hwnd: HWND, csidl: c_int, hToken: HANDLE, dwFlags: DWORD, pszPath: LPWSTR) -> HRESULT --- - SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR --- + SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR --- Shell_NotifyIconW :: proc(dwMessage: DWORD, lpData: ^NOTIFYICONDATAW) -> BOOL --- + + SHGetKnownFolderIDList :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppidl: rawptr) -> HRESULT --- + SHSetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, pszPath: PCWSTR ) -> HRESULT --- + SHGetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppszPath: ^LPWSTR) -> HRESULT --- } APPBARDATA :: struct { @@ -36,16 +40,16 @@ APPBARDATA :: struct { lParam: LPARAM, } PAPPBARDATA :: ^APPBARDATA - + ABM_NEW :: 0x00000000 ABM_REMOVE :: 0x00000001 ABM_QUERYPOS :: 0x00000002 ABM_SETPOS :: 0x00000003 ABM_GETSTATE :: 0x00000004 ABM_GETTASKBARPOS :: 0x00000005 -ABM_ACTIVATE :: 0x00000006 +ABM_ACTIVATE :: 0x00000006 ABM_GETAUTOHIDEBAR :: 0x00000007 -ABM_SETAUTOHIDEBAR :: 0x00000008 +ABM_SETAUTOHIDEBAR :: 0x00000008 ABM_WINDOWPOSCHANGED :: 0x0000009 ABM_SETSTATE :: 0x0000000a ABN_STATECHANGE :: 0x0000000 @@ -58,3 +62,32 @@ ABE_LEFT :: 0 ABE_TOP :: 1 ABE_RIGHT :: 2 ABE_BOTTOM :: 3 + +KNOWNFOLDERID :: GUID +REFKNOWNFOLDERID :: ^KNOWNFOLDERID + +KNOWN_FOLDER_FLAG :: enum u32 { + DEFAULT = 0x00000000, + + // if NTDDI_VERSION >= NTDDI_WIN10_RS3 + FORCE_APP_DATA_REDIRECTION = 0x00080000, + + // if NTDDI_VERSION >= NTDDI_WIN10_RS2 + RETURN_FILTER_REDIRECTION_TARGET = 0x00040000, + FORCE_PACKAGE_REDIRECTION = 0x00020000, + NO_PACKAGE_REDIRECTION = 0x00010000, + FORCE_APPCONTAINER_REDIRECTION = 0x00020000, + + // if NTDDI_VERSION >= NTDDI_WIN7 + NO_APPCONTAINER_REDIRECTION = 0x00010000, + + CREATE = 0x00008000, + DONT_VERIFY = 0x00004000, + DONT_UNEXPAND = 0x00002000, + NO_ALIAS = 0x00001000, + INIT = 0x00000800, + DEFAULT_PATH = 0x00000400, + NOT_PARENT_RELATIVE = 0x00000200, + SIMPLE_IDLIST = 0x00000100, + ALIAS_ONLY = 0x80000000, +} From 21247721b441d3a78b33b2e2ce5042fcae58f8e1 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Sat, 28 Oct 2023 20:39:46 +0200 Subject: [PATCH 010/160] Add WaitFor* Ex variants --- core/sys/windows/kernel32.odin | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 0c612a974..439b96078 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -172,6 +172,7 @@ foreign kernel32 { TolerableDelay: ULONG, ) -> BOOL --- WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD --- + WaitForSingleObjectEx :: proc(hHandle: HANDLE, dwMilliseconds: DWORD, bAlterable: BOOL) -> DWORD --- Sleep :: proc(dwMilliseconds: DWORD) --- GetProcessId :: proc(handle: HANDLE) -> DWORD --- CopyFileW :: proc( @@ -320,6 +321,13 @@ foreign kernel32 { bWaitAll: BOOL, dwMilliseconds: DWORD, ) -> DWORD --- + WaitForMultipleObjectsEx :: proc( + nCount: DWORD, + lpHandles: ^HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD, + bAlterable: BOOL, + ) -> DWORD --- CreateNamedPipeW :: proc( lpName: LPCWSTR, dwOpenMode: DWORD, From 5c533e477d4100ff083220e9bea1fc5dd5d799d2 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:32:53 +0100 Subject: [PATCH 011/160] Fix indentation and style --- core/sys/windows/dbghelp.odin | 298 ++++++++++++++-------------- core/sys/windows/known_folders.odin | 284 +++++++++++++------------- core/sys/windows/shell32.odin | 34 ++-- 3 files changed, 308 insertions(+), 308 deletions(-) diff --git a/core/sys/windows/dbghelp.odin b/core/sys/windows/dbghelp.odin index baddbc58e..a32060313 100644 --- a/core/sys/windows/dbghelp.odin +++ b/core/sys/windows/dbghelp.odin @@ -6,37 +6,37 @@ foreign import "system:Dbghelp.lib" RVA :: DWORD MINIDUMP_LOCATION_DESCRIPTOR :: struct { - DataSize: ULONG32, - Rva: RVA, + DataSize: ULONG32, + Rva: RVA, } MINIDUMP_DIRECTORY :: struct { - StreamType: ULONG32, - Location: MINIDUMP_LOCATION_DESCRIPTOR, + StreamType: ULONG32, + Location: MINIDUMP_LOCATION_DESCRIPTOR, } MINIDUMP_EXCEPTION_INFORMATION :: struct { - ThreadId: DWORD, - ExceptionPointers: ^EXCEPTION_POINTERS, - ClientPointers: BOOL, + ThreadId: DWORD, + ExceptionPointers: ^EXCEPTION_POINTERS, + ClientPointers: BOOL, } MINIDUMP_MEMORY_INFO :: struct { - BaseAddress: ULONG64, - AllocationBase: ULONG64, - AllocationProtect: ULONG32, - __alignment1: ULONG32, - RegionSize: ULONG64, - State: ULONG32, - Protect: ULONG32, - Type: ULONG32, - __alignment2: ULONG32, + BaseAddress: ULONG64, + AllocationBase: ULONG64, + AllocationProtect: ULONG32, + __alignment1: ULONG32, + RegionSize: ULONG64, + State: ULONG32, + Protect: ULONG32, + Type: ULONG32, + __alignment2: ULONG32, } MINIDUMP_USER_STREAM :: struct { - Type: ULONG32, - BufferSize: ULONG, - Buffer: PVOID, + Type: ULONG32, + BufferSize: ULONG, + Buffer: PVOID, } MINIDUMP_USER_STREAM_INFORMATION :: struct { @@ -51,52 +51,52 @@ MINIDUMP_CALLBACK_ROUTINE :: #type proc "stdcall" ( ) -> BOOL MINIDUMP_CALLBACK_INFORMATION :: struct { - CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE, - CallbackParam: PVOID, + CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE, + CallbackParam: PVOID, } MINIDUMP_CALLBACK_INPUT :: struct { - ProcessId: ULONG, - ProcessHandle: HANDLE, - CallbackType: ULONG, - using _: struct #raw_union { - Status: HRESULT, - Thread: MINIDUMP_THREAD_CALLBACK, - ThreadEx: MINIDUMP_THREAD_EX_CALLBACK, - Module: MINIDUMP_MODULE_CALLBACK, - IncludeThread: MINIDUMP_INCLUDE_THREAD_CALLBACK, - IncludeModule: MINIDUMP_INCLUDE_MODULE_CALLBACK, - Io: MINIDUMP_IO_CALLBACK, - ReadMemoryFailure: MINIDUMP_READ_MEMORY_FAILURE_CALLBACK, - SecondaryFlags: ULONG, - VmQuery: MINIDUMP_VM_QUERY_CALLBACK, - VmPreRead: MINIDUMP_VM_PRE_READ_CALLBACK, - VmPostRead: MINIDUMP_VM_POST_READ_CALLBACK, - }, + ProcessId: ULONG, + ProcessHandle: HANDLE, + CallbackType: ULONG, + using _: struct #raw_union { + Status: HRESULT, + Thread: MINIDUMP_THREAD_CALLBACK, + ThreadEx: MINIDUMP_THREAD_EX_CALLBACK, + Module: MINIDUMP_MODULE_CALLBACK, + IncludeThread: MINIDUMP_INCLUDE_THREAD_CALLBACK, + IncludeModule: MINIDUMP_INCLUDE_MODULE_CALLBACK, + Io: MINIDUMP_IO_CALLBACK, + ReadMemoryFailure: MINIDUMP_READ_MEMORY_FAILURE_CALLBACK, + SecondaryFlags: ULONG, + VmQuery: MINIDUMP_VM_QUERY_CALLBACK, + VmPreRead: MINIDUMP_VM_PRE_READ_CALLBACK, + VmPostRead: MINIDUMP_VM_POST_READ_CALLBACK, + }, } _MINIDUMP_ARM64_PAD :: ULONG when ODIN_ARCH == .arm64 else struct {} MINIDUMP_THREAD_CALLBACK :: struct { - ThreadId: ULONG, - ThreadHandle: HANDLE, - Pad: _MINIDUMP_ARM64_PAD, - Context: CONTEXT, - SizeOfContext: ULONG, - StackBase: ULONG64, - StackEnd: ULONG64, + ThreadId: ULONG, + ThreadHandle: HANDLE, + Pad: _MINIDUMP_ARM64_PAD, + Context: CONTEXT, + SizeOfContext: ULONG, + StackBase: ULONG64, + StackEnd: ULONG64, } MINIDUMP_THREAD_EX_CALLBACK :: struct { - ThreadId: ULONG, - ThreadHandle: HANDLE, - Pad: _MINIDUMP_ARM64_PAD, - Context: CONTEXT, - SizeOfContext: ULONG, - StackBase: ULONG64, - StackEnd: ULONG64, - BackingStoreBase: ULONG64, - BackingStoreEnd: ULONG64, + ThreadId: ULONG, + ThreadHandle: HANDLE, + Pad: _MINIDUMP_ARM64_PAD, + Context: CONTEXT, + SizeOfContext: ULONG, + StackBase: ULONG64, + StackEnd: ULONG64, + BackingStoreBase: ULONG64, + BackingStoreEnd: ULONG64, } MINIDUMP_INCLUDE_THREAD_CALLBACK :: struct { @@ -105,32 +105,32 @@ MINIDUMP_INCLUDE_THREAD_CALLBACK :: struct { // NOTE(jakubtomsu): From verrsrc.h VS_FIXEDFILEINFO :: struct { - dwSignature: DWORD, /* e.g. 0xfeef04bd */ - dwStrucVersion: DWORD, /* e.g. 0x00000042 = "0.42" */ - dwFileVersionMS: DWORD, /* e.g. 0x00030075 = "3.75" */ - dwFileVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */ - dwProductVersionMS: DWORD, /* e.g. 0x00030010 = "3.10" */ - dwProductVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */ - dwFileFlagsMask: DWORD, /* = 0x3F for version "0.42" */ - dwFileFlags: DWORD, /* e.g. VFF_DEBUG | VFF_PRERELEASE */ - dwFileOS: DWORD, /* e.g. VOS_DOS_WINDOWS16 */ - dwFileType: DWORD, /* e.g. VFT_DRIVER */ - dwFileSubtype: DWORD, /* e.g. VFT2_DRV_KEYBOARD */ - dwFileDateMS: DWORD, /* e.g. 0 */ - dwFileDateLS: DWORD, /* e.g. 0 */ + dwSignature: DWORD, /* e.g. 0xfeef04bd */ + dwStrucVersion: DWORD, /* e.g. 0x00000042 = "0.42" */ + dwFileVersionMS: DWORD, /* e.g. 0x00030075 = "3.75" */ + dwFileVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */ + dwProductVersionMS: DWORD, /* e.g. 0x00030010 = "3.10" */ + dwProductVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */ + dwFileFlagsMask: DWORD, /* = 0x3F for version "0.42" */ + dwFileFlags: DWORD, /* e.g. VFF_DEBUG | VFF_PRERELEASE */ + dwFileOS: DWORD, /* e.g. VOS_DOS_WINDOWS16 */ + dwFileType: DWORD, /* e.g. VFT_DRIVER */ + dwFileSubtype: DWORD, /* e.g. VFT2_DRV_KEYBOARD */ + dwFileDateMS: DWORD, /* e.g. 0 */ + dwFileDateLS: DWORD, /* e.g. 0 */ } MINIDUMP_MODULE_CALLBACK :: struct { - FullPath: ^WCHAR, - BaseOfImage: ULONG64, - SizeOfImage: ULONG, - CheckSum: ULONG, - TimeDateStamp: ULONG, - VersionInfo: VS_FIXEDFILEINFO, - CvRecord: PVOID, - SizeOfCvRecord: ULONG, - MiscRecord: PVOID, - SizeOfMiscRecord: ULONG, + FullPath: ^WCHAR, + BaseOfImage: ULONG64, + SizeOfImage: ULONG, + CheckSum: ULONG, + TimeDateStamp: ULONG, + VersionInfo: VS_FIXEDFILEINFO, + CvRecord: PVOID, + SizeOfCvRecord: ULONG, + MiscRecord: PVOID, + SizeOfMiscRecord: ULONG, } MINIDUMP_INCLUDE_MODULE_CALLBACK :: struct { @@ -138,16 +138,16 @@ MINIDUMP_INCLUDE_MODULE_CALLBACK :: struct { } MINIDUMP_IO_CALLBACK :: struct { - Handle: HANDLE, - Offset: ULONG64, - Buffer: PVOID, - BufferBytes: ULONG, + Handle: HANDLE, + Offset: ULONG64, + Buffer: PVOID, + BufferBytes: ULONG, } MINIDUMP_READ_MEMORY_FAILURE_CALLBACK :: struct { - Offset: ULONG64, - Bytes: ULONG, - FailureStatus: HRESULT, + Offset: ULONG64, + Bytes: ULONG, + FailureStatus: HRESULT, } MINIDUMP_VM_QUERY_CALLBACK :: struct { @@ -156,76 +156,76 @@ MINIDUMP_VM_QUERY_CALLBACK :: struct { MINIDUMP_VM_PRE_READ_CALLBACK :: struct { Offset: ULONG64, - Buffer: PVOID, - Size: ULONG, + Buffer: PVOID, + Size: ULONG, } MINIDUMP_VM_POST_READ_CALLBACK :: struct { Offset: ULONG64, - Buffer: PVOID, - Size: ULONG, - Completed: ULONG, - Status: HRESULT, + Buffer: PVOID, + Size: ULONG, + Completed: ULONG, + Status: HRESULT, } MINIDUMP_CALLBACK_OUTPUT :: struct { - using _: struct #raw_union { - ModuleWriteFlags: ULONG, - ThreadWriteFlags: ULONG, - SecondaryFlags: ULONG, - using _: struct { - MemoryBase: ULONG64, - MemorySize: ULONG, - }, - using _: struct { - CheckCancel: BOOL, - Cancel: BOOL, - }, - Handle: HANDLE, - using _: struct { - VmRegion: MINIDUMP_MEMORY_INFO, - Continue: BOOL, - }, - using _: struct { - VmQueryStatus: HRESULT, - VmQueryResult: MINIDUMP_MEMORY_INFO, - }, - using _: struct { - VmReadStatus: HRESULT, - VmReadBytesCompleted: ULONG, - }, - Status: HRESULT, - }, + using _: struct #raw_union { + ModuleWriteFlags: ULONG, + ThreadWriteFlags: ULONG, + SecondaryFlags: ULONG, + using _: struct { + MemoryBase: ULONG64, + MemorySize: ULONG, + }, + using _: struct { + CheckCancel: BOOL, + Cancel: BOOL, + }, + Handle: HANDLE, + using _: struct { + VmRegion: MINIDUMP_MEMORY_INFO, + Continue: BOOL, + }, + using _: struct { + VmQueryStatus: HRESULT, + VmQueryResult: MINIDUMP_MEMORY_INFO, + }, + using _: struct { + VmReadStatus: HRESULT, + VmReadBytesCompleted: ULONG, + }, + Status: HRESULT, + }, } MINIDUMP_TYPE :: enum u32 { - Normal = 0x00000000, - WithDataSegs = 0x00000001, - WithFullMemory = 0x00000002, - WithHandleData = 0x00000004, - FilterMemory = 0x00000008, - ScanMemory = 0x00000010, - WithUnloadedModules = 0x00000020, - WithIndirectlyReferencedMemory = 0x00000040, - FilterModulePaths = 0x00000080, - WithProcessThreadData = 0x00000100, - WithPrivateReadWriteMemory = 0x00000200, - WithoutOptionalData = 0x00000400, - WithFullMemoryInfo = 0x00000800, - WithThreadInfo = 0x00001000, - WithCodeSegs = 0x00002000, - WithoutAuxiliaryState = 0x00004000, - WithFullAuxiliaryState = 0x00008000, - WithPrivateWriteCopyMemory = 0x00010000, - IgnoreInaccessibleMemory = 0x00020000, - WithTokenInformation = 0x00040000, - WithModuleHeaders = 0x00080000, - FilterTriage = 0x00100000, - WithAvxXStateContext = 0x00200000, - WithIptTrace = 0x00400000, - ScanInaccessiblePartialPages = 0x00800000, - FilterWriteCombinedMemory = 0x01000000, - ValidTypeFlags = 0x01ffffff, + Normal = 0x00000000, + WithDataSegs = 0x00000001, + WithFullMemory = 0x00000002, + WithHandleData = 0x00000004, + FilterMemory = 0x00000008, + ScanMemory = 0x00000010, + WithUnloadedModules = 0x00000020, + WithIndirectlyReferencedMemory = 0x00000040, + FilterModulePaths = 0x00000080, + WithProcessThreadData = 0x00000100, + WithPrivateReadWriteMemory = 0x00000200, + WithoutOptionalData = 0x00000400, + WithFullMemoryInfo = 0x00000800, + WithThreadInfo = 0x00001000, + WithCodeSegs = 0x00002000, + WithoutAuxiliaryState = 0x00004000, + WithFullAuxiliaryState = 0x00008000, + WithPrivateWriteCopyMemory = 0x00010000, + IgnoreInaccessibleMemory = 0x00020000, + WithTokenInformation = 0x00040000, + WithModuleHeaders = 0x00080000, + FilterTriage = 0x00100000, + WithAvxXStateContext = 0x00200000, + WithIptTrace = 0x00400000, + ScanInaccessiblePartialPages = 0x00800000, + FilterWriteCombinedMemory = 0x01000000, + ValidTypeFlags = 0x01ffffff, } @(default_calling_convention = "stdcall") @@ -241,10 +241,10 @@ foreign Dbghelp { ) -> BOOL --- MiniDumpReadDumpStream :: proc( - BaseOfDump: PVOID, - StreamNumber: ULONG, - Dir: ^^MINIDUMP_DIRECTORY, - StreamPointer: ^PVOID, - StreamSize: ^ULONG, + BaseOfDump: PVOID, + StreamNumber: ULONG, + Dir: ^^MINIDUMP_DIRECTORY, + StreamPointer: ^PVOID, + StreamSize: ^ULONG, ) -> BOOL --- } diff --git a/core/sys/windows/known_folders.odin b/core/sys/windows/known_folders.odin index 43e132e17..439d65faf 100644 --- a/core/sys/windows/known_folders.odin +++ b/core/sys/windows/known_folders.odin @@ -1,145 +1,145 @@ // +build windows package sys_windows -FOLDERID_NetworkFolder: GUID : {0xD20BEEC4, 0x5CA8, 0x4905, {0xAE, 0x3B, 0xBF, 0x25, 0x1E, 0xA0, 0x9B, 0x53}} -FOLDERID_ComputerFolder: GUID : {0x0AC0837C, 0xBBF8, 0x452A, {0x85, 0x0D, 0x79, 0xD0, 0x8E, 0x66, 0x7C, 0xA7}} -FOLDERID_InternetFolder: GUID : {0x4D9F7874, 0x4E0C, 0x4904, {0x96, 0x7B, 0x40, 0xB0, 0xD2, 0x0C, 0x3E, 0x4B}} -FOLDERID_ControlPanelFolder: GUID : {0x82A74AEB, 0xAEB4, 0x465C, {0xA0, 0x14, 0xD0, 0x97, 0xEE, 0x34, 0x6D, 0x63}} -FOLDERID_PrintersFolder: GUID : {0x76FC4E2D, 0xD6AD, 0x4519, {0xA6, 0x63, 0x37, 0xBD, 0x56, 0x06, 0x81, 0x85}} -FOLDERID_SyncManagerFolder: GUID : {0x43668BF8, 0xC14E, 0x49B2, {0x97, 0xC9, 0x74, 0x77, 0x84, 0xD7, 0x84, 0xB7}} -FOLDERID_SyncSetupFolder: GUID : {0xf214138 , 0xb1d3, 0x4a90, {0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a}} -FOLDERID_ConflictFolder: GUID : {0x4bfefb45, 0x347d, 0x4006, {0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92}} -FOLDERID_SyncResultsFolder: GUID : {0x289a9a43, 0xbe44, 0x4057, {0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9}} -FOLDERID_RecycleBinFolder: GUID : {0xB7534046, 0x3ECB, 0x4C18, {0xBE, 0x4E, 0x64, 0xCD, 0x4C, 0xB7, 0xD6, 0xAC}} -FOLDERID_ConnectionsFolder: GUID : {0x6F0CD92B, 0x2E97, 0x45D1, {0x88, 0xFF, 0xB0, 0xD1, 0x86, 0xB8, 0xDE, 0xDD}} -FOLDERID_Fonts: GUID : {0xFD228CB7, 0xAE11, 0x4AE3, {0x86, 0x4C, 0x16, 0xF3, 0x91, 0x0A, 0xB8, 0xFE}} -FOLDERID_Desktop: GUID : {0xB4BFCC3A, 0xDB2C, 0x424C, {0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41}} -FOLDERID_Startup: GUID : {0xB97D20BB, 0xF46A, 0x4C97, {0xBA, 0x10, 0x5E, 0x36, 0x08, 0x43, 0x08, 0x54}} -FOLDERID_Programs: GUID : {0xA77F5D77, 0x2E2B, 0x44C3, {0xA6, 0xA2, 0xAB, 0xA6, 0x01, 0x05, 0x4A, 0x51}} -FOLDERID_StartMenu: GUID : {0x625B53C3, 0xAB48, 0x4EC1, {0xBA, 0x1F, 0xA1, 0xEF, 0x41, 0x46, 0xFC, 0x19}} -FOLDERID_Recent: GUID : {0xAE50C081, 0xEBD2, 0x438A, {0x86, 0x55, 0x8A, 0x09, 0x2E, 0x34, 0x98, 0x7A}} -FOLDERID_SendTo: GUID : {0x8983036C, 0x27C0, 0x404B, {0x8F, 0x08, 0x10, 0x2D, 0x10, 0xDC, 0xFD, 0x74}} -FOLDERID_Documents: GUID : {0xFDD39AD0, 0x238F, 0x46AF, {0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7}} -FOLDERID_Favorites: GUID : {0x1777F761, 0x68AD, 0x4D8A, {0x87, 0xBD, 0x30, 0xB7, 0x59, 0xFA, 0x33, 0xDD}} -FOLDERID_NetHood: GUID : {0xC5ABBF53, 0xE17F, 0x4121, {0x89, 0x00, 0x86, 0x62, 0x6F, 0xC2, 0xC9, 0x73}} -FOLDERID_PrintHood: GUID : {0x9274BD8D, 0xCFD1, 0x41C3, {0xB3, 0x5E, 0xB1, 0x3F, 0x55, 0xA7, 0x58, 0xF4}} -FOLDERID_Templates: GUID : {0xA63293E8, 0x664E, 0x48DB, {0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7}} -FOLDERID_CommonStartup: GUID : {0x82A5EA35, 0xD9CD, 0x47C5, {0x96, 0x29, 0xE1, 0x5D, 0x2F, 0x71, 0x4E, 0x6E}} -FOLDERID_CommonPrograms: GUID : {0x0139D44E, 0x6AFE, 0x49F2, {0x86, 0x90, 0x3D, 0xAF, 0xCA, 0xE6, 0xFF, 0xB8}} -FOLDERID_CommonStartMenu: GUID : {0xA4115719, 0xD62E, 0x491D, {0xAA, 0x7C, 0xE7, 0x4B, 0x8B, 0xE3, 0xB0, 0x67}} -FOLDERID_PublicDesktop: GUID : {0xC4AA340D, 0xF20F, 0x4863, {0xAF, 0xEF, 0xF8, 0x7E, 0xF2, 0xE6, 0xBA, 0x25}} -FOLDERID_ProgramData: GUID : {0x62AB5D82, 0xFDC1, 0x4DC3, {0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97}} -FOLDERID_CommonTemplates: GUID : {0xB94237E7, 0x57AC, 0x4347, {0x91, 0x51, 0xB0, 0x8C, 0x6C, 0x32, 0xD1, 0xF7}} -FOLDERID_PublicDocuments: GUID : {0xED4824AF, 0xDCE4, 0x45A8, {0x81, 0xE2, 0xFC, 0x79, 0x65, 0x08, 0x36, 0x34}} -FOLDERID_RoamingAppData: GUID : {0x3EB685DB, 0x65F9, 0x4CF6, {0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D}} -FOLDERID_LocalAppData: GUID : {0xF1B32785, 0x6FBA, 0x4FCF, {0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91}} -FOLDERID_LocalAppDataLow: GUID : {0xA520A1A4, 0x1780, 0x4FF6, {0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16}} -FOLDERID_InternetCache: GUID : {0x352481E8, 0x33BE, 0x4251, {0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D}} -FOLDERID_Cookies: GUID : {0x2B0F765D, 0xC0E9, 0x4171, {0x90, 0x8E, 0x08, 0xA6, 0x11, 0xB8, 0x4F, 0xF6}} -FOLDERID_History: GUID : {0xD9DC8A3B, 0xB784, 0x432E, {0xA7, 0x81, 0x5A, 0x11, 0x30, 0xA7, 0x59, 0x63}} -FOLDERID_System: GUID : {0x1AC14E77, 0x02E7, 0x4E5D, {0xB7, 0x44, 0x2E, 0xB1, 0xAE, 0x51, 0x98, 0xB7}} -FOLDERID_SystemX86: GUID : {0xD65231B0, 0xB2F1, 0x4857, {0xA4, 0xCE, 0xA8, 0xE7, 0xC6, 0xEA, 0x7D, 0x27}} -FOLDERID_Windows: GUID : {0xF38BF404, 0x1D43, 0x42F2, {0x93, 0x05, 0x67, 0xDE, 0x0B, 0x28, 0xFC, 0x23}} -FOLDERID_Profile: GUID : {0x5E6C858F, 0x0E22, 0x4760, {0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73}} -FOLDERID_Pictures: GUID : {0x33E28130, 0x4E1E, 0x4676, {0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB}} -FOLDERID_ProgramFilesX86: GUID : {0x7C5A40EF, 0xA0FB, 0x4BFC, {0x87, 0x4A, 0xC0, 0xF2, 0xE0, 0xB9, 0xFA, 0x8E}} -FOLDERID_ProgramFilesCommonX86: GUID : {0xDE974D24, 0xD9C6, 0x4D3E, {0xBF, 0x91, 0xF4, 0x45, 0x51, 0x20, 0xB9, 0x17}} -FOLDERID_ProgramFilesX64: GUID : {0x6d809377, 0x6af0, 0x444b, {0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e}} -FOLDERID_ProgramFilesCommonX64: GUID : {0x6365d5a7, 0xf0d , 0x45e5, {0x87, 0xf6, 0xd, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d }} -FOLDERID_ProgramFiles: GUID : {0x905e63b6, 0xc1bf, 0x494e, {0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a}} -FOLDERID_ProgramFilesCommon: GUID : {0xF7F1ED05, 0x9F6D, 0x47A2, {0xAA, 0xAE, 0x29, 0xD3, 0x17, 0xC6, 0xF0, 0x66}} -FOLDERID_UserProgramFiles: GUID : {0x5cd7aee2, 0x2219, 0x4a67, {0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb}} -FOLDERID_UserProgramFilesCommon: GUID : {0xbcbd3057, 0xca5c, 0x4622, {0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16}} -FOLDERID_AdminTools: GUID : {0x724EF170, 0xA42D, 0x4FEF, {0x9F, 0x26, 0xB6, 0x0E, 0x84, 0x6F, 0xBA, 0x4F}} -FOLDERID_CommonAdminTools: GUID : {0xD0384E7D, 0xBAC3, 0x4797, {0x8F, 0x14, 0xCB, 0xA2, 0x29, 0xB3, 0x92, 0xB5}} -FOLDERID_Music: GUID : {0x4BD8D571, 0x6D19, 0x48D3, {0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43}} -FOLDERID_Videos: GUID : {0x18989B1D, 0x99B5, 0x455B, {0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC}} -FOLDERID_Ringtones: GUID : {0xC870044B, 0xF49E, 0x4126, {0xA9, 0xC3, 0xB5, 0x2A, 0x1F, 0xF4, 0x11, 0xE8}} -FOLDERID_PublicPictures: GUID : {0xB6EBFB86, 0x6907, 0x413C, {0x9A, 0xF7, 0x4F, 0xC2, 0xAB, 0xF0, 0x7C, 0xC5}} -FOLDERID_PublicMusic: GUID : {0x3214FAB5, 0x9757, 0x4298, {0xBB, 0x61, 0x92, 0xA9, 0xDE, 0xAA, 0x44, 0xFF}} -FOLDERID_PublicVideos: GUID : {0x2400183A, 0x6185, 0x49FB, {0xA2, 0xD8, 0x4A, 0x39, 0x2A, 0x60, 0x2B, 0xA3}} -FOLDERID_PublicRingtones: GUID : {0xE555AB60, 0x153B, 0x4D17, {0x9F, 0x04, 0xA5, 0xFE, 0x99, 0xFC, 0x15, 0xEC}} -FOLDERID_ResourceDir: GUID : {0x8AD10C31, 0x2ADB, 0x4296, {0xA8, 0xF7, 0xE4, 0x70, 0x12, 0x32, 0xC9, 0x72}} -FOLDERID_LocalizedResourcesDir: GUID : {0x2A00375E, 0x224C, 0x49DE, {0xB8, 0xD1, 0x44, 0x0D, 0xF7, 0xEF, 0x3D, 0xDC}} -FOLDERID_CommonOEMLinks: GUID : {0xC1BAE2D0, 0x10DF, 0x4334, {0xBE, 0xDD, 0x7A, 0xA2, 0x0B, 0x22, 0x7A, 0x9D}} -FOLDERID_CDBurning: GUID : {0x9E52AB10, 0xF80D, 0x49DF, {0xAC, 0xB8, 0x43, 0x30, 0xF5, 0x68, 0x78, 0x55}} -FOLDERID_UserProfiles: GUID : {0x0762D272, 0xC50A, 0x4BB0, {0xA3, 0x82, 0x69, 0x7D, 0xCD, 0x72, 0x9B, 0x80}} -FOLDERID_Playlists: GUID : {0xDE92C1C7, 0x837F, 0x4F69, {0xA3, 0xBB, 0x86, 0xE6, 0x31, 0x20, 0x4A, 0x23}} -FOLDERID_SamplePlaylists: GUID : {0x15CA69B3, 0x30EE, 0x49C1, {0xAC, 0xE1, 0x6B, 0x5E, 0xC3, 0x72, 0xAF, 0xB5}} -FOLDERID_SampleMusic: GUID : {0xB250C668, 0xF57D, 0x4EE1, {0xA6, 0x3C, 0x29, 0x0E, 0xE7, 0xD1, 0xAA, 0x1F}} -FOLDERID_SamplePictures: GUID : {0xC4900540, 0x2379, 0x4C75, {0x84, 0x4B, 0x64, 0xE6, 0xFA, 0xF8, 0x71, 0x6B}} -FOLDERID_SampleVideos: GUID : {0x859EAD94, 0x2E85, 0x48AD, {0xA7, 0x1A, 0x09, 0x69, 0xCB, 0x56, 0xA6, 0xCD}} -FOLDERID_PhotoAlbums: GUID : {0x69D2CF90, 0xFC33, 0x4FB7, {0x9A, 0x0C, 0xEB, 0xB0, 0xF0, 0xFC, 0xB4, 0x3C}} -FOLDERID_Public: GUID : {0xDFDF76A2, 0xC82A, 0x4D63, {0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85}} -FOLDERID_ChangeRemovePrograms: GUID : {0xdf7266ac, 0x9274, 0x4867, {0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d}} -FOLDERID_AppUpdates: GUID : {0xa305ce99, 0xf527, 0x492b, {0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4}} -FOLDERID_AddNewPrograms: GUID : {0xde61d971, 0x5ebc, 0x4f02, {0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04}} -FOLDERID_Downloads: GUID : {0x374de290, 0x123f, 0x4565, {0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}} -FOLDERID_PublicDownloads: GUID : {0x3d644c9b, 0x1fb8, 0x4f30, {0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0}} -FOLDERID_SavedSearches: GUID : {0x7d1d3a04, 0xdebb, 0x4115, {0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda}} -FOLDERID_QuickLaunch: GUID : {0x52a4f021, 0x7b75, 0x48a9, {0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f}} -FOLDERID_Contacts: GUID : {0x56784854, 0xc6cb, 0x462b, {0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82}} -FOLDERID_SidebarParts: GUID : {0xa75d362e, 0x50fc, 0x4fb7, {0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93}} -FOLDERID_SidebarDefaultParts: GUID : {0x7b396e54, 0x9ec5, 0x4300, {0xbe, 0xa , 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26}} -FOLDERID_PublicGameTasks: GUID : {0xdebf2536, 0xe1a8, 0x4c59, {0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea}} -FOLDERID_GameTasks: GUID : {0x54fae61 , 0x4dd8, 0x4787, {0x80, 0xb6, 0x9 , 0x2 , 0x20, 0xc4, 0xb7, 0x0 }} -FOLDERID_SavedGames: GUID : {0x4c5c32ff, 0xbb9d, 0x43b0, {0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}} -FOLDERID_Games: GUID : {0xcac52c1a, 0xb53d, 0x4edc, {0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34}} -FOLDERID_SEARCH_MAPI: GUID : {0x98ec0e18, 0x2098, 0x4d44, {0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81}} -FOLDERID_SEARCH_CSC: GUID : {0xee32e446, 0x31ca, 0x4aba, {0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e}} -FOLDERID_Links: GUID : {0xbfb9d5e0, 0xc6a9, 0x404c, {0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68}} -FOLDERID_UsersFiles: GUID : {0xf3ce0f7c, 0x4901, 0x4acc, {0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f}} -FOLDERID_UsersLibraries: GUID : {0xa302545d, 0xdeff, 0x464b, {0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b}} -FOLDERID_SearchHome: GUID : {0x190337d1, 0xb8ca, 0x4121, {0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a}} -FOLDERID_OriginalImages: GUID : {0x2C36C0AA, 0x5812, 0x4b87, {0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39}} -FOLDERID_DocumentsLibrary: GUID : {0x7b0db17d, 0x9cd2, 0x4a93, {0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c}} -FOLDERID_MusicLibrary: GUID : {0x2112ab0a, 0xc86a, 0x4ffe, {0xa3, 0x68, 0xd , 0xe9, 0x6e, 0x47, 0x1 , 0x2e}} -FOLDERID_PicturesLibrary: GUID : {0xa990ae9f, 0xa03b, 0x4e80, {0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x4 }} -FOLDERID_VideosLibrary: GUID : {0x491e922f, 0x5643, 0x4af4, {0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74}} -FOLDERID_RecordedTVLibrary: GUID : {0x1a6fdba2, 0xf42d, 0x4358, {0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5}} -FOLDERID_HomeGroup: GUID : {0x52528a6b, 0xb9e3, 0x4add, {0xb6, 0xd , 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d}} -FOLDERID_HomeGroupCurrentUser: GUID : {0x9b74b6a3, 0xdfd , 0x4f11, {0x9e, 0x78, 0x5f, 0x78, 0x0 , 0xf2, 0xe7, 0x72}} -FOLDERID_DeviceMetadataStore: GUID : {0x5ce4a5e9, 0xe4eb, 0x479d, {0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55}} -FOLDERID_Libraries: GUID : {0x1b3ea5dc, 0xb587, 0x4786, {0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae}} -FOLDERID_PublicLibraries: GUID : {0x48daf80b, 0xe6cf, 0x4f4e, {0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84}} -FOLDERID_UserPinned: GUID : {0x9e3995ab, 0x1f9c, 0x4f13, {0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74}} -FOLDERID_ImplicitAppShortcuts: GUID : {0xbcb5256f, 0x79f6, 0x4cee, {0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x2 , 0xfd, 0x46}} -FOLDERID_AccountPictures: GUID : {0x008ca0b1, 0x55b4, 0x4c56, {0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe}} -FOLDERID_PublicUserTiles: GUID : {0x0482af6c, 0x08f1, 0x4c34, {0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17}} -FOLDERID_AppsFolder: GUID : {0x1e87508d, 0x89c2, 0x42f0, {0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}} -FOLDERID_StartMenuAllPrograms: GUID : {0xf26305ef, 0x6948, 0x40b9, {0xb2, 0x55, 0x81, 0x45, 0x3d, 0x9 , 0xc7, 0x85}} -FOLDERID_CommonStartMenuPlaces: GUID : {0xa440879f, 0x87a0, 0x4f7d, {0xb7, 0x0 , 0x2 , 0x7 , 0xb9, 0x66, 0x19, 0x4a}} -FOLDERID_ApplicationShortcuts: GUID : {0xa3918781, 0xe5f2, 0x4890, {0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c}} -FOLDERID_RoamingTiles: GUID : {0xbcfc5a , 0xed94, 0x4e48, {0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90}} -FOLDERID_RoamedTileImages: GUID : {0xaaa8d5a5, 0xf1d6, 0x4259, {0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e}} -FOLDERID_Screenshots: GUID : {0xb7bede81, 0xdf94, 0x4682, {0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f}} -FOLDERID_CameraRoll: GUID : {0xab5fb87b, 0x7ce2, 0x4f83, {0x91, 0x5d, 0x55, 0x8 , 0x46, 0xc9, 0x53, 0x7b}} -FOLDERID_SkyDrive: GUID : {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}} -FOLDERID_OneDrive: GUID : {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}} -FOLDERID_SkyDriveDocuments: GUID : {0x24d89e24, 0x2f19, 0x4534, {0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe}} -FOLDERID_SkyDrivePictures: GUID : {0x339719b5, 0x8c47, 0x4894, {0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6}} -FOLDERID_SkyDriveMusic: GUID : {0xc3f2459e, 0x80d6, 0x45dc, {0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30}} -FOLDERID_SkyDriveCameraRoll: GUID : {0x767e6811, 0x49cb, 0x4273, {0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b}} -FOLDERID_SearchHistory: GUID : {0x0d4c3db6, 0x03a3, 0x462f, {0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4}} -FOLDERID_SearchTemplates: GUID : {0x7e636bfe, 0xdfa9, 0x4d5e, {0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9}} -FOLDERID_CameraRollLibrary: GUID : {0x2b20df75, 0x1eda, 0x4039, {0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7}} -FOLDERID_SavedPictures: GUID : {0x3b193882, 0xd3ad, 0x4eab, {0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f}} -FOLDERID_SavedPicturesLibrary: GUID : {0xe25b5812, 0xbe88, 0x4bd9, {0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3}} -FOLDERID_RetailDemo: GUID : {0x12d4c69e, 0x24ad, 0x4923, {0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67}} -FOLDERID_Device: GUID : {0x1C2AC1DC, 0x4358, 0x4B6C, {0x97, 0x33, 0xAF, 0x21, 0x15, 0x65, 0x76, 0xF0}} -FOLDERID_DevelopmentFiles: GUID : {0xdbe8e08e, 0x3053, 0x4bbc, {0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59}} -FOLDERID_Objects3D: GUID : {0x31c0dd25, 0x9439, 0x4f12, {0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22}} -FOLDERID_AppCaptures: GUID : {0xedc0fe71, 0x98d8, 0x4f4a, {0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65}} -FOLDERID_LocalDocuments: GUID : {0xf42ee2d3, 0x909f, 0x4907, {0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56}} -FOLDERID_LocalPictures: GUID : {0x0ddd015d, 0xb06c, 0x45d5, {0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39}} -FOLDERID_LocalVideos: GUID : {0x35286a68, 0x3c57, 0x41a1, {0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95}} -FOLDERID_LocalMusic: GUID : {0xa0c69a99, 0x21c8, 0x4671, {0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d}} -FOLDERID_LocalDownloads: GUID : {0x7d83ee9b, 0x2244, 0x4e70, {0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4}} -FOLDERID_RecordedCalls: GUID : {0x2f8b40c2, 0x83ed, 0x48ee, {0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a}} -FOLDERID_AllAppMods: GUID : {0x7ad67899, 0x66af, 0x43ba, {0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96}} -FOLDERID_CurrentAppMods: GUID : {0x3db40b20, 0x2a30, 0x4dbe, {0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99}} -FOLDERID_AppDataDesktop: GUID : {0xb2c5e279, 0x7add, 0x439f, {0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72}} -FOLDERID_AppDataDocuments: GUID : {0x7be16610, 0x1f7f, 0x44ac, {0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1}} -FOLDERID_AppDataFavorites: GUID : {0x7cfbefbc, 0xde1f, 0x45aa, {0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9}} -FOLDERID_AppDataProgramData: GUID : {0x559d40a3, 0xa036, 0x40fa, {0xaf, 0x61, 0x84, 0xcb, 0x43, 0xa , 0x4d, 0x34}} -FOLDERID_LocalStorage: GUID : {0xB3EB08D3, 0xA1F3, 0x496B, {0x86, 0x5A, 0x42, 0xB5, 0x36, 0xCD, 0xA0, 0xEC}} +FOLDERID_NetworkFolder :: GUID {0xD20BEEC4, 0x5CA8, 0x4905, {0xAE, 0x3B, 0xBF, 0x25, 0x1E, 0xA0, 0x9B, 0x53}} +FOLDERID_ComputerFolder :: GUID {0x0AC0837C, 0xBBF8, 0x452A, {0x85, 0x0D, 0x79, 0xD0, 0x8E, 0x66, 0x7C, 0xA7}} +FOLDERID_InternetFolder :: GUID {0x4D9F7874, 0x4E0C, 0x4904, {0x96, 0x7B, 0x40, 0xB0, 0xD2, 0x0C, 0x3E, 0x4B}} +FOLDERID_ControlPanelFolder :: GUID {0x82A74AEB, 0xAEB4, 0x465C, {0xA0, 0x14, 0xD0, 0x97, 0xEE, 0x34, 0x6D, 0x63}} +FOLDERID_PrintersFolder :: GUID {0x76FC4E2D, 0xD6AD, 0x4519, {0xA6, 0x63, 0x37, 0xBD, 0x56, 0x06, 0x81, 0x85}} +FOLDERID_SyncManagerFolder :: GUID {0x43668BF8, 0xC14E, 0x49B2, {0x97, 0xC9, 0x74, 0x77, 0x84, 0xD7, 0x84, 0xB7}} +FOLDERID_SyncSetupFolder :: GUID {0xf214138 , 0xb1d3, 0x4a90, {0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a}} +FOLDERID_ConflictFolder :: GUID {0x4bfefb45, 0x347d, 0x4006, {0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92}} +FOLDERID_SyncResultsFolder :: GUID {0x289a9a43, 0xbe44, 0x4057, {0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9}} +FOLDERID_RecycleBinFolder :: GUID {0xB7534046, 0x3ECB, 0x4C18, {0xBE, 0x4E, 0x64, 0xCD, 0x4C, 0xB7, 0xD6, 0xAC}} +FOLDERID_ConnectionsFolder :: GUID {0x6F0CD92B, 0x2E97, 0x45D1, {0x88, 0xFF, 0xB0, 0xD1, 0x86, 0xB8, 0xDE, 0xDD}} +FOLDERID_Fonts :: GUID {0xFD228CB7, 0xAE11, 0x4AE3, {0x86, 0x4C, 0x16, 0xF3, 0x91, 0x0A, 0xB8, 0xFE}} +FOLDERID_Desktop :: GUID {0xB4BFCC3A, 0xDB2C, 0x424C, {0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41}} +FOLDERID_Startup :: GUID {0xB97D20BB, 0xF46A, 0x4C97, {0xBA, 0x10, 0x5E, 0x36, 0x08, 0x43, 0x08, 0x54}} +FOLDERID_Programs :: GUID {0xA77F5D77, 0x2E2B, 0x44C3, {0xA6, 0xA2, 0xAB, 0xA6, 0x01, 0x05, 0x4A, 0x51}} +FOLDERID_StartMenu :: GUID {0x625B53C3, 0xAB48, 0x4EC1, {0xBA, 0x1F, 0xA1, 0xEF, 0x41, 0x46, 0xFC, 0x19}} +FOLDERID_Recent :: GUID {0xAE50C081, 0xEBD2, 0x438A, {0x86, 0x55, 0x8A, 0x09, 0x2E, 0x34, 0x98, 0x7A}} +FOLDERID_SendTo :: GUID {0x8983036C, 0x27C0, 0x404B, {0x8F, 0x08, 0x10, 0x2D, 0x10, 0xDC, 0xFD, 0x74}} +FOLDERID_Documents :: GUID {0xFDD39AD0, 0x238F, 0x46AF, {0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7}} +FOLDERID_Favorites :: GUID {0x1777F761, 0x68AD, 0x4D8A, {0x87, 0xBD, 0x30, 0xB7, 0x59, 0xFA, 0x33, 0xDD}} +FOLDERID_NetHood :: GUID {0xC5ABBF53, 0xE17F, 0x4121, {0x89, 0x00, 0x86, 0x62, 0x6F, 0xC2, 0xC9, 0x73}} +FOLDERID_PrintHood :: GUID {0x9274BD8D, 0xCFD1, 0x41C3, {0xB3, 0x5E, 0xB1, 0x3F, 0x55, 0xA7, 0x58, 0xF4}} +FOLDERID_Templates :: GUID {0xA63293E8, 0x664E, 0x48DB, {0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7}} +FOLDERID_CommonStartup :: GUID {0x82A5EA35, 0xD9CD, 0x47C5, {0x96, 0x29, 0xE1, 0x5D, 0x2F, 0x71, 0x4E, 0x6E}} +FOLDERID_CommonPrograms :: GUID {0x0139D44E, 0x6AFE, 0x49F2, {0x86, 0x90, 0x3D, 0xAF, 0xCA, 0xE6, 0xFF, 0xB8}} +FOLDERID_CommonStartMenu :: GUID {0xA4115719, 0xD62E, 0x491D, {0xAA, 0x7C, 0xE7, 0x4B, 0x8B, 0xE3, 0xB0, 0x67}} +FOLDERID_PublicDesktop :: GUID {0xC4AA340D, 0xF20F, 0x4863, {0xAF, 0xEF, 0xF8, 0x7E, 0xF2, 0xE6, 0xBA, 0x25}} +FOLDERID_ProgramData :: GUID {0x62AB5D82, 0xFDC1, 0x4DC3, {0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97}} +FOLDERID_CommonTemplates :: GUID {0xB94237E7, 0x57AC, 0x4347, {0x91, 0x51, 0xB0, 0x8C, 0x6C, 0x32, 0xD1, 0xF7}} +FOLDERID_PublicDocuments :: GUID {0xED4824AF, 0xDCE4, 0x45A8, {0x81, 0xE2, 0xFC, 0x79, 0x65, 0x08, 0x36, 0x34}} +FOLDERID_RoamingAppData :: GUID {0x3EB685DB, 0x65F9, 0x4CF6, {0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D}} +FOLDERID_LocalAppData :: GUID {0xF1B32785, 0x6FBA, 0x4FCF, {0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91}} +FOLDERID_LocalAppDataLow :: GUID {0xA520A1A4, 0x1780, 0x4FF6, {0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16}} +FOLDERID_InternetCache :: GUID {0x352481E8, 0x33BE, 0x4251, {0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D}} +FOLDERID_Cookies :: GUID {0x2B0F765D, 0xC0E9, 0x4171, {0x90, 0x8E, 0x08, 0xA6, 0x11, 0xB8, 0x4F, 0xF6}} +FOLDERID_History :: GUID {0xD9DC8A3B, 0xB784, 0x432E, {0xA7, 0x81, 0x5A, 0x11, 0x30, 0xA7, 0x59, 0x63}} +FOLDERID_System :: GUID {0x1AC14E77, 0x02E7, 0x4E5D, {0xB7, 0x44, 0x2E, 0xB1, 0xAE, 0x51, 0x98, 0xB7}} +FOLDERID_SystemX86 :: GUID {0xD65231B0, 0xB2F1, 0x4857, {0xA4, 0xCE, 0xA8, 0xE7, 0xC6, 0xEA, 0x7D, 0x27}} +FOLDERID_Windows :: GUID {0xF38BF404, 0x1D43, 0x42F2, {0x93, 0x05, 0x67, 0xDE, 0x0B, 0x28, 0xFC, 0x23}} +FOLDERID_Profile :: GUID {0x5E6C858F, 0x0E22, 0x4760, {0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73}} +FOLDERID_Pictures :: GUID {0x33E28130, 0x4E1E, 0x4676, {0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB}} +FOLDERID_ProgramFilesX86 :: GUID {0x7C5A40EF, 0xA0FB, 0x4BFC, {0x87, 0x4A, 0xC0, 0xF2, 0xE0, 0xB9, 0xFA, 0x8E}} +FOLDERID_ProgramFilesCommonX86 :: GUID {0xDE974D24, 0xD9C6, 0x4D3E, {0xBF, 0x91, 0xF4, 0x45, 0x51, 0x20, 0xB9, 0x17}} +FOLDERID_ProgramFilesX64 :: GUID {0x6d809377, 0x6af0, 0x444b, {0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e}} +FOLDERID_ProgramFilesCommonX64 :: GUID {0x6365d5a7, 0xf0d , 0x45e5, {0x87, 0xf6, 0xd, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d }} +FOLDERID_ProgramFiles :: GUID {0x905e63b6, 0xc1bf, 0x494e, {0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a}} +FOLDERID_ProgramFilesCommon :: GUID {0xF7F1ED05, 0x9F6D, 0x47A2, {0xAA, 0xAE, 0x29, 0xD3, 0x17, 0xC6, 0xF0, 0x66}} +FOLDERID_UserProgramFiles :: GUID {0x5cd7aee2, 0x2219, 0x4a67, {0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb}} +FOLDERID_UserProgramFilesCommon :: GUID {0xbcbd3057, 0xca5c, 0x4622, {0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16}} +FOLDERID_AdminTools :: GUID {0x724EF170, 0xA42D, 0x4FEF, {0x9F, 0x26, 0xB6, 0x0E, 0x84, 0x6F, 0xBA, 0x4F}} +FOLDERID_CommonAdminTools :: GUID {0xD0384E7D, 0xBAC3, 0x4797, {0x8F, 0x14, 0xCB, 0xA2, 0x29, 0xB3, 0x92, 0xB5}} +FOLDERID_Music :: GUID {0x4BD8D571, 0x6D19, 0x48D3, {0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43}} +FOLDERID_Videos :: GUID {0x18989B1D, 0x99B5, 0x455B, {0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC}} +FOLDERID_Ringtones :: GUID {0xC870044B, 0xF49E, 0x4126, {0xA9, 0xC3, 0xB5, 0x2A, 0x1F, 0xF4, 0x11, 0xE8}} +FOLDERID_PublicPictures :: GUID {0xB6EBFB86, 0x6907, 0x413C, {0x9A, 0xF7, 0x4F, 0xC2, 0xAB, 0xF0, 0x7C, 0xC5}} +FOLDERID_PublicMusic :: GUID {0x3214FAB5, 0x9757, 0x4298, {0xBB, 0x61, 0x92, 0xA9, 0xDE, 0xAA, 0x44, 0xFF}} +FOLDERID_PublicVideos :: GUID {0x2400183A, 0x6185, 0x49FB, {0xA2, 0xD8, 0x4A, 0x39, 0x2A, 0x60, 0x2B, 0xA3}} +FOLDERID_PublicRingtones :: GUID {0xE555AB60, 0x153B, 0x4D17, {0x9F, 0x04, 0xA5, 0xFE, 0x99, 0xFC, 0x15, 0xEC}} +FOLDERID_ResourceDir :: GUID {0x8AD10C31, 0x2ADB, 0x4296, {0xA8, 0xF7, 0xE4, 0x70, 0x12, 0x32, 0xC9, 0x72}} +FOLDERID_LocalizedResourcesDir :: GUID {0x2A00375E, 0x224C, 0x49DE, {0xB8, 0xD1, 0x44, 0x0D, 0xF7, 0xEF, 0x3D, 0xDC}} +FOLDERID_CommonOEMLinks :: GUID {0xC1BAE2D0, 0x10DF, 0x4334, {0xBE, 0xDD, 0x7A, 0xA2, 0x0B, 0x22, 0x7A, 0x9D}} +FOLDERID_CDBurning :: GUID {0x9E52AB10, 0xF80D, 0x49DF, {0xAC, 0xB8, 0x43, 0x30, 0xF5, 0x68, 0x78, 0x55}} +FOLDERID_UserProfiles :: GUID {0x0762D272, 0xC50A, 0x4BB0, {0xA3, 0x82, 0x69, 0x7D, 0xCD, 0x72, 0x9B, 0x80}} +FOLDERID_Playlists :: GUID {0xDE92C1C7, 0x837F, 0x4F69, {0xA3, 0xBB, 0x86, 0xE6, 0x31, 0x20, 0x4A, 0x23}} +FOLDERID_SamplePlaylists :: GUID {0x15CA69B3, 0x30EE, 0x49C1, {0xAC, 0xE1, 0x6B, 0x5E, 0xC3, 0x72, 0xAF, 0xB5}} +FOLDERID_SampleMusic :: GUID {0xB250C668, 0xF57D, 0x4EE1, {0xA6, 0x3C, 0x29, 0x0E, 0xE7, 0xD1, 0xAA, 0x1F}} +FOLDERID_SamplePictures :: GUID {0xC4900540, 0x2379, 0x4C75, {0x84, 0x4B, 0x64, 0xE6, 0xFA, 0xF8, 0x71, 0x6B}} +FOLDERID_SampleVideos :: GUID {0x859EAD94, 0x2E85, 0x48AD, {0xA7, 0x1A, 0x09, 0x69, 0xCB, 0x56, 0xA6, 0xCD}} +FOLDERID_PhotoAlbums :: GUID {0x69D2CF90, 0xFC33, 0x4FB7, {0x9A, 0x0C, 0xEB, 0xB0, 0xF0, 0xFC, 0xB4, 0x3C}} +FOLDERID_Public :: GUID {0xDFDF76A2, 0xC82A, 0x4D63, {0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85}} +FOLDERID_ChangeRemovePrograms :: GUID {0xdf7266ac, 0x9274, 0x4867, {0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d}} +FOLDERID_AppUpdates :: GUID {0xa305ce99, 0xf527, 0x492b, {0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4}} +FOLDERID_AddNewPrograms :: GUID {0xde61d971, 0x5ebc, 0x4f02, {0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04}} +FOLDERID_Downloads :: GUID {0x374de290, 0x123f, 0x4565, {0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}} +FOLDERID_PublicDownloads :: GUID {0x3d644c9b, 0x1fb8, 0x4f30, {0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0}} +FOLDERID_SavedSearches :: GUID {0x7d1d3a04, 0xdebb, 0x4115, {0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda}} +FOLDERID_QuickLaunch :: GUID {0x52a4f021, 0x7b75, 0x48a9, {0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f}} +FOLDERID_Contacts :: GUID {0x56784854, 0xc6cb, 0x462b, {0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82}} +FOLDERID_SidebarParts :: GUID {0xa75d362e, 0x50fc, 0x4fb7, {0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93}} +FOLDERID_SidebarDefaultParts :: GUID {0x7b396e54, 0x9ec5, 0x4300, {0xbe, 0xa , 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26}} +FOLDERID_PublicGameTasks :: GUID {0xdebf2536, 0xe1a8, 0x4c59, {0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea}} +FOLDERID_GameTasks :: GUID {0x54fae61 , 0x4dd8, 0x4787, {0x80, 0xb6, 0x9 , 0x2 , 0x20, 0xc4, 0xb7, 0x0 }} +FOLDERID_SavedGames :: GUID {0x4c5c32ff, 0xbb9d, 0x43b0, {0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}} +FOLDERID_Games :: GUID {0xcac52c1a, 0xb53d, 0x4edc, {0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34}} +FOLDERID_SEARCH_MAPI :: GUID {0x98ec0e18, 0x2098, 0x4d44, {0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81}} +FOLDERID_SEARCH_CSC :: GUID {0xee32e446, 0x31ca, 0x4aba, {0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e}} +FOLDERID_Links :: GUID {0xbfb9d5e0, 0xc6a9, 0x404c, {0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68}} +FOLDERID_UsersFiles :: GUID {0xf3ce0f7c, 0x4901, 0x4acc, {0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f}} +FOLDERID_UsersLibraries :: GUID {0xa302545d, 0xdeff, 0x464b, {0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b}} +FOLDERID_SearchHome :: GUID {0x190337d1, 0xb8ca, 0x4121, {0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a}} +FOLDERID_OriginalImages :: GUID {0x2C36C0AA, 0x5812, 0x4b87, {0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39}} +FOLDERID_DocumentsLibrary :: GUID {0x7b0db17d, 0x9cd2, 0x4a93, {0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c}} +FOLDERID_MusicLibrary :: GUID {0x2112ab0a, 0xc86a, 0x4ffe, {0xa3, 0x68, 0xd , 0xe9, 0x6e, 0x47, 0x1 , 0x2e}} +FOLDERID_PicturesLibrary :: GUID {0xa990ae9f, 0xa03b, 0x4e80, {0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x4 }} +FOLDERID_VideosLibrary :: GUID {0x491e922f, 0x5643, 0x4af4, {0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74}} +FOLDERID_RecordedTVLibrary :: GUID {0x1a6fdba2, 0xf42d, 0x4358, {0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5}} +FOLDERID_HomeGroup :: GUID {0x52528a6b, 0xb9e3, 0x4add, {0xb6, 0xd , 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d}} +FOLDERID_HomeGroupCurrentUser :: GUID {0x9b74b6a3, 0xdfd , 0x4f11, {0x9e, 0x78, 0x5f, 0x78, 0x0 , 0xf2, 0xe7, 0x72}} +FOLDERID_DeviceMetadataStore :: GUID {0x5ce4a5e9, 0xe4eb, 0x479d, {0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55}} +FOLDERID_Libraries :: GUID {0x1b3ea5dc, 0xb587, 0x4786, {0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae}} +FOLDERID_PublicLibraries :: GUID {0x48daf80b, 0xe6cf, 0x4f4e, {0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84}} +FOLDERID_UserPinned :: GUID {0x9e3995ab, 0x1f9c, 0x4f13, {0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74}} +FOLDERID_ImplicitAppShortcuts :: GUID {0xbcb5256f, 0x79f6, 0x4cee, {0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x2 , 0xfd, 0x46}} +FOLDERID_AccountPictures :: GUID {0x008ca0b1, 0x55b4, 0x4c56, {0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe}} +FOLDERID_PublicUserTiles :: GUID {0x0482af6c, 0x08f1, 0x4c34, {0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17}} +FOLDERID_AppsFolder :: GUID {0x1e87508d, 0x89c2, 0x42f0, {0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}} +FOLDERID_StartMenuAllPrograms :: GUID {0xf26305ef, 0x6948, 0x40b9, {0xb2, 0x55, 0x81, 0x45, 0x3d, 0x9 , 0xc7, 0x85}} +FOLDERID_CommonStartMenuPlaces :: GUID {0xa440879f, 0x87a0, 0x4f7d, {0xb7, 0x0 , 0x2 , 0x7 , 0xb9, 0x66, 0x19, 0x4a}} +FOLDERID_ApplicationShortcuts :: GUID {0xa3918781, 0xe5f2, 0x4890, {0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c}} +FOLDERID_RoamingTiles :: GUID {0xbcfc5a , 0xed94, 0x4e48, {0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90}} +FOLDERID_RoamedTileImages :: GUID {0xaaa8d5a5, 0xf1d6, 0x4259, {0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e}} +FOLDERID_Screenshots :: GUID {0xb7bede81, 0xdf94, 0x4682, {0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f}} +FOLDERID_CameraRoll :: GUID {0xab5fb87b, 0x7ce2, 0x4f83, {0x91, 0x5d, 0x55, 0x8 , 0x46, 0xc9, 0x53, 0x7b}} +FOLDERID_SkyDrive :: GUID {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}} +FOLDERID_OneDrive :: GUID {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}} +FOLDERID_SkyDriveDocuments :: GUID {0x24d89e24, 0x2f19, 0x4534, {0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe}} +FOLDERID_SkyDrivePictures :: GUID {0x339719b5, 0x8c47, 0x4894, {0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6}} +FOLDERID_SkyDriveMusic :: GUID {0xc3f2459e, 0x80d6, 0x45dc, {0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30}} +FOLDERID_SkyDriveCameraRoll :: GUID {0x767e6811, 0x49cb, 0x4273, {0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b}} +FOLDERID_SearchHistory :: GUID {0x0d4c3db6, 0x03a3, 0x462f, {0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4}} +FOLDERID_SearchTemplates :: GUID {0x7e636bfe, 0xdfa9, 0x4d5e, {0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9}} +FOLDERID_CameraRollLibrary :: GUID {0x2b20df75, 0x1eda, 0x4039, {0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7}} +FOLDERID_SavedPictures :: GUID {0x3b193882, 0xd3ad, 0x4eab, {0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f}} +FOLDERID_SavedPicturesLibrary :: GUID {0xe25b5812, 0xbe88, 0x4bd9, {0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3}} +FOLDERID_RetailDemo :: GUID {0x12d4c69e, 0x24ad, 0x4923, {0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67}} +FOLDERID_Device :: GUID {0x1C2AC1DC, 0x4358, 0x4B6C, {0x97, 0x33, 0xAF, 0x21, 0x15, 0x65, 0x76, 0xF0}} +FOLDERID_DevelopmentFiles :: GUID {0xdbe8e08e, 0x3053, 0x4bbc, {0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59}} +FOLDERID_Objects3D :: GUID {0x31c0dd25, 0x9439, 0x4f12, {0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22}} +FOLDERID_AppCaptures :: GUID {0xedc0fe71, 0x98d8, 0x4f4a, {0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65}} +FOLDERID_LocalDocuments :: GUID {0xf42ee2d3, 0x909f, 0x4907, {0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56}} +FOLDERID_LocalPictures :: GUID {0x0ddd015d, 0xb06c, 0x45d5, {0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39}} +FOLDERID_LocalVideos :: GUID {0x35286a68, 0x3c57, 0x41a1, {0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95}} +FOLDERID_LocalMusic :: GUID {0xa0c69a99, 0x21c8, 0x4671, {0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d}} +FOLDERID_LocalDownloads :: GUID {0x7d83ee9b, 0x2244, 0x4e70, {0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4}} +FOLDERID_RecordedCalls :: GUID {0x2f8b40c2, 0x83ed, 0x48ee, {0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a}} +FOLDERID_AllAppMods :: GUID {0x7ad67899, 0x66af, 0x43ba, {0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96}} +FOLDERID_CurrentAppMods :: GUID {0x3db40b20, 0x2a30, 0x4dbe, {0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99}} +FOLDERID_AppDataDesktop :: GUID {0xb2c5e279, 0x7add, 0x439f, {0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72}} +FOLDERID_AppDataDocuments :: GUID {0x7be16610, 0x1f7f, 0x44ac, {0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1}} +FOLDERID_AppDataFavorites :: GUID {0x7cfbefbc, 0xde1f, 0x45aa, {0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9}} +FOLDERID_AppDataProgramData :: GUID {0x559d40a3, 0xa036, 0x40fa, {0xaf, 0x61, 0x84, 0xcb, 0x43, 0xa , 0x4d, 0x34}} +FOLDERID_LocalStorage :: GUID {0xB3EB08D3, 0xA1F3, 0x496B, {0x86, 0x5A, 0x42, 0xB5, 0x36, 0xCD, 0xA0, 0xEC}} diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin index f6aaf2c95..2d2b257df 100644 --- a/core/sys/windows/shell32.odin +++ b/core/sys/windows/shell32.odin @@ -28,7 +28,7 @@ foreign shell32 { SHGetKnownFolderIDList :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppidl: rawptr) -> HRESULT --- SHSetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, pszPath: PCWSTR ) -> HRESULT --- - SHGetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppszPath: ^LPWSTR) -> HRESULT --- + SHGetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppszPath: ^LPWSTR) -> HRESULT --- } APPBARDATA :: struct { @@ -67,27 +67,27 @@ KNOWNFOLDERID :: GUID REFKNOWNFOLDERID :: ^KNOWNFOLDERID KNOWN_FOLDER_FLAG :: enum u32 { - DEFAULT = 0x00000000, + DEFAULT = 0x00000000, // if NTDDI_VERSION >= NTDDI_WIN10_RS3 - FORCE_APP_DATA_REDIRECTION = 0x00080000, + FORCE_APP_DATA_REDIRECTION = 0x00080000, // if NTDDI_VERSION >= NTDDI_WIN10_RS2 - RETURN_FILTER_REDIRECTION_TARGET = 0x00040000, - FORCE_PACKAGE_REDIRECTION = 0x00020000, - NO_PACKAGE_REDIRECTION = 0x00010000, - FORCE_APPCONTAINER_REDIRECTION = 0x00020000, + RETURN_FILTER_REDIRECTION_TARGET = 0x00040000, + FORCE_PACKAGE_REDIRECTION = 0x00020000, + NO_PACKAGE_REDIRECTION = 0x00010000, + FORCE_APPCONTAINER_REDIRECTION = 0x00020000, // if NTDDI_VERSION >= NTDDI_WIN7 - NO_APPCONTAINER_REDIRECTION = 0x00010000, + NO_APPCONTAINER_REDIRECTION = 0x00010000, - CREATE = 0x00008000, - DONT_VERIFY = 0x00004000, - DONT_UNEXPAND = 0x00002000, - NO_ALIAS = 0x00001000, - INIT = 0x00000800, - DEFAULT_PATH = 0x00000400, - NOT_PARENT_RELATIVE = 0x00000200, - SIMPLE_IDLIST = 0x00000100, - ALIAS_ONLY = 0x80000000, + CREATE = 0x00008000, + DONT_VERIFY = 0x00004000, + DONT_UNEXPAND = 0x00002000, + NO_ALIAS = 0x00001000, + INIT = 0x00000800, + DEFAULT_PATH = 0x00000400, + NOT_PARENT_RELATIVE = 0x00000200, + SIMPLE_IDLIST = 0x00000100, + ALIAS_ONLY = 0x80000000, } From 9b68671082fc1d20f65da1ed56fbcc3eb45296ca Mon Sep 17 00:00:00 2001 From: Laytan Date: Tue, 31 Oct 2023 19:29:54 +0100 Subject: [PATCH 012/160] Fix empty pass because of trailing comma --- src/llvm_backend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 513b40a4d..276abc2d4 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1827,7 +1827,7 @@ cgscc( function-attrs, function( require - ), + ) ) ), deadargelim, From 864b29f7f1cf5977aefbcb85c8a76a84790fba9a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Nov 2023 13:57:20 +0000 Subject: [PATCH 013/160] Add missing calls --- src/llvm_backend_expr.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index bde975d96..3455bedff 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1069,6 +1069,7 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV args[1] = rhs; switch (type_size_of(ft)) { + case 2: return lb_emit_runtime_call(p, "quo_complex32", args); case 4: return lb_emit_runtime_call(p, "quo_complex64", args); case 8: return lb_emit_runtime_call(p, "quo_complex128", args); default: GB_PANIC("Unknown float type"); break; @@ -1145,6 +1146,7 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV args[1] = rhs; switch (8*type_size_of(ft)) { + case 16: return lb_emit_runtime_call(p, "mul_quaternion64", args); case 32: return lb_emit_runtime_call(p, "mul_quaternion128", args); case 64: return lb_emit_runtime_call(p, "mul_quaternion256", args); default: GB_PANIC("Unknown float type"); break; @@ -1157,6 +1159,7 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV args[1] = rhs; switch (8*type_size_of(ft)) { + case 16: return lb_emit_runtime_call(p, "quo_quaternion64", args); case 32: return lb_emit_runtime_call(p, "quo_quaternion128", args); case 64: return lb_emit_runtime_call(p, "quo_quaternion256", args); default: GB_PANIC("Unknown float type"); break; From ef5eb4b612eed1a51186b9182a5e61b79ce36d06 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Nov 2023 13:59:39 +0000 Subject: [PATCH 014/160] A docs.odin explaining what are the required entities in core:runtime by the compiler --- core/runtime/docs.odin | 179 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 core/runtime/docs.odin diff --git a/core/runtime/docs.odin b/core/runtime/docs.odin new file mode 100644 index 000000000..a520584c5 --- /dev/null +++ b/core/runtime/docs.odin @@ -0,0 +1,179 @@ +package runtime + +/* + +package runtime has numerous entities (declarations) which are required by the compiler to function. + + +## Basic types and calls (and anything they rely on) + +Source_Code_Location +Context +Allocator +Logger + +__init_context +_cleanup_runtime + + +## cstring calls + +cstring_to_string +cstring_len + + + +## Required when RTTI is enabled (the vast majority of targets) + +Type_Info + +type_table +__type_info_of + + +## Hashing + +default_hasher +default_hasher_cstring +default_hasher_string + + +## Pseudo-CRT required procedured due to LLVM but useful in general +memset +memcpy +memove + + +## Procedures required by the LLVM backend +umodti3 +udivti3 +modti3 +divti3 +fixdfti +fixunsdfti +fixunsdfdi +floattidf +floattidf_unsigned +truncsfhf2 +truncdfhf2 +gnu_h2f_ieee +gnu_f2h_ieee +extendhfsf2 +__ashlti3 // wasm specific +__multi3 // wasm specific + + + +## Required an entry point is defined (i.e. 'main') + +args__ + + +## When -no-crt is defined (and not a wasm target) (mostly due to LLVM) +_tls_index +_fltused + + +## Bounds checking procedures (when not disabled with -no-bounds-check) + +bounds_check_error +matrix_bounds_check_error +slice_expr_error_hi +slice_expr_error_lo_hi +multi_pointer_slice_expr_error + + +## Type assertion check + +type_assertion_check +type_assertion_check2 // takes in typeid + + +## Arithmetic + +quo_complex32 +quo_complex64 +quo_complex128 + +mul_quaternion64 +mul_quaternion128 +mul_quaternion256 + +quo_quaternion64 +quo_quaternion128 +quo_quaternion256 + +abs_complex32 +abs_complex64 +abs_complex128 + +abs_quaternion64 +abs_quaternion128 +abs_quaternion256 + + +## Comparison + +memory_equal +memory_compare +memory_compare_zero + +cstring_eq +cstring_ne +cstring_lt +cstring_gt +cstring_le +cstring_gt + +string_eq +string_ne +string_lt +string_gt +string_le +string_gt + +complex32_eq +complex32_ne +complex64_eq +complex64_ne +complex128_eq +complex128_ne + +quaternion64_eq +quaternion64_ne +quaternion128_eq +quaternion128_ne +quaternion256_eq +quaternion256_ne + + +## Map specific calls + +map_seed_from_map_data +__dynamic_map_check_grow // static map calls +map_insert_hash_dynamic // static map calls +__dynamic_map_get // dynamic map calls +__dynamic_map_set // dynamic map calls + + +## Dynamic literals ([dymamic]T and map[K]V) (can be disabled with -no-dynamic-literals) + +__dynamic_array_reserve +__dynamic_array_append + +__dynamic_map_reserve + + +## Objective-C specific + +objc_lookUpClass +sel_registerName +objc_allocateClassPair + + +## for-in `string` type + +string_decode_rune +string_decode_last_rune // #reverse for + +*/ \ No newline at end of file From e206d6ba35796e2aab97c7741dc52d44317350c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 3 Nov 2023 13:26:33 +0000 Subject: [PATCH 015/160] Add `allocator` parameter to `fmt`'s `aprint` and `aprintln` --- core/fmt/fmt.odin | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 1f52fdea9..f0d70e415 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -120,9 +120,9 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist // // Returns: A formatted string. // -aprint :: proc(args: ..any, sep := " ") -> string { +aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder - strings.builder_init(&str) + strings.builder_init(&str, allocator) sbprint(&str, ..args, sep=sep) return strings.to_string(str) } @@ -136,9 +136,9 @@ aprint :: proc(args: ..any, sep := " ") -> string { // // Returns: A formatted string with a newline character at the end. // -aprintln :: proc(args: ..any, sep := " ") -> string { +aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder - strings.builder_init(&str) + strings.builder_init(&str, allocator) sbprintln(&str, ..args, sep=sep) return strings.to_string(str) } From 1f969fdc75fc30e9d242eebad701d20625e9657a Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Fri, 3 Nov 2023 15:06:46 +0100 Subject: [PATCH 016/160] Fix tabs --- core/sys/windows/dbghelp.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sys/windows/dbghelp.odin b/core/sys/windows/dbghelp.odin index a32060313..7c63b845b 100644 --- a/core/sys/windows/dbghelp.odin +++ b/core/sys/windows/dbghelp.odin @@ -40,8 +40,8 @@ MINIDUMP_USER_STREAM :: struct { } MINIDUMP_USER_STREAM_INFORMATION :: struct { - UserStreamCount: ULONG, - UserStreamArray: ^MINIDUMP_USER_STREAM, + UserStreamCount: ULONG, + UserStreamArray: ^MINIDUMP_USER_STREAM, } MINIDUMP_CALLBACK_ROUTINE :: #type proc "stdcall" ( From 4a4aca6829a97ebfcdab3bdd84ca0524002a6cd8 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sat, 4 Nov 2023 20:30:14 +1100 Subject: [PATCH 017/160] [math]: Fix the doc comments on F64_* constants --- core/math/math.odin | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/math/math.odin b/core/math/math.odin index 4215a8075..4a56040f8 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -2261,17 +2261,17 @@ F32_NORMALIZE :: 0 F32_RADIX :: 2 F32_ROUNDS :: 1 -F64_DIG :: 15 // # of decimal digits of precision -F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0 -F64_MANT_DIG :: 53 // # of bits in mantissa -F64_MAX :: 1.7976931348623158e+308 // max value -F64_MAX_10_EXP :: 308 // max decimal exponent -F64_MAX_EXP :: 1024 // max binary exponent -F64_MIN :: 2.2250738585072014e-308 // min positive value -F64_MIN_10_EXP :: -307 // min decimal exponent -F64_MIN_EXP :: -1021 // min binary exponent -F64_RADIX :: 2 // exponent radix -F64_ROUNDS :: 1 // addition rounding: near +F64_DIG :: 15 // Number of representable decimal digits. +F64_EPSILON :: 2.2204460492503131e-016 // Smallest number such that `1.0 + F64_EPSILON != 1.0`. +F64_MANT_DIG :: 53 // Number of bits in the mantissa. +F64_MAX :: 1.7976931348623158e+308 // Maximum representable value. +F64_MAX_10_EXP :: 308 // Maximum base-10 exponent yielding normalized value. +F64_MAX_EXP :: 1024 // One greater than the maximum possible base-2 exponent yielding normalized value. +F64_MIN :: 2.2250738585072014e-308 // Minimum positive normalized value. +F64_MIN_10_EXP :: -307 // Minimum base-10 exponent yielding normalized value. +F64_MIN_EXP :: -1021 // One greater than the minimum possible base-2 exponent yielding normalized value. +F64_RADIX :: 2 // Exponent radix. +F64_ROUNDS :: 1 // Addition rounding: near. F16_MASK :: 0x1f From ce5e7998ba235d3f444220f4093bf52d8615af21 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 4 Nov 2023 11:22:06 +0000 Subject: [PATCH 018/160] Add warning for things like `1.0 / some_int` --- src/check_expr.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2ee761b9c..d85f119c3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3558,6 +3558,30 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ return; } + switch (op.kind) { + case Token_Quo: + case Token_Mod: + case Token_ModMod: + case Token_QuoEq: + case Token_ModEq: + case Token_ModModEq: + if (is_type_integer(y->type) && !is_type_untyped(y->type) && + is_type_float(x->type) && is_type_untyped(x->type)) { + char const *suggestion = "\tSuggestion: Try explicitly casting the constant value for clarity"; + + gbString t = type_to_string(y->type); + if (x->value.kind != ExactValue_Invalid) { + gbString s = exact_value_to_string(x->value); + warning(node, "Dividing an untyped float '%s' by '%s' will perform integer division\n%s", s, t, suggestion); + gb_string_free(s); + } else { + warning(node, "Dividing an untyped float by '%s' will perform integer division\n%s", t, suggestion); + } + gb_string_free(t); + } + break; + } + convert_to_typed(c, x, y->type); if (x->mode == Addressing_Invalid) { return; From 5edb2c568840248f63de3fab58a02f134f182525 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 4 Nov 2023 14:53:42 +0000 Subject: [PATCH 019/160] Fix #2913 --- src/check_expr.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d85f119c3..5cc548739 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2768,6 +2768,11 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod gb_string_free(to_type); x->mode = Addressing_Invalid; } + } else if (!is_type_integer(x->type)) { + gbString x_str = expr_to_string(x->expr); + error(node, "Non-integer shifted operand '%s' is not allowed", x_str); + gb_string_free(x_str); + x->mode = Addressing_Invalid; } // x->value = x_val; return; From 9e36e28217bfef6cd3f054c88faef8aa25313b5c Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Sat, 4 Nov 2023 17:40:13 +0100 Subject: [PATCH 020/160] Update d3d12.odin --- vendor/directx/d3d12/d3d12.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin index 9c61aacbe..30b543e43 100644 --- a/vendor/directx/d3d12/d3d12.odin +++ b/vendor/directx/d3d12/d3d12.odin @@ -1905,7 +1905,6 @@ DESCRIPTOR_HEAP_TYPE :: enum i32 { SAMPLER = 1, RTV = 2, DSV = 3, - NUM_TYPES = 4, } DESCRIPTOR_HEAP_FLAGS :: distinct bit_set[DESCRIPTOR_HEAP_FLAG; u32] From 620128046801eb6b5156e58e386d2b42a4e7ae68 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 4 Nov 2023 22:14:44 +0100 Subject: [PATCH 021/160] Add math.pow2_f{16,32,64}, fast floating point 2^x where x is an integer. --- core/math/math.odin | 49 +++++++++++++++++++++++++- tests/internal/Makefile | 7 ++-- tests/internal/build.bat | 3 +- tests/internal/test_pow.odin | 67 ++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 tests/internal/test_pow.odin diff --git a/core/math/math.odin b/core/math/math.odin index 4215a8075..a5d86cffb 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -203,7 +203,54 @@ pow10_f64 :: proc "contextless" (n: f64) -> f64 { return 0 } +pow2_f64 :: proc(#any_int exp: int) -> (res: f64) { + switch { + case exp >= -1022 && exp <= 1023: // Normal + return transmute(f64)(u64(exp + F64_BIAS) << F64_SHIFT) + case exp < -1075: // Underflow + return f64(0) + case exp == -1075: // Underflow + return 0h00000000_00000001 + case exp < -1022: // Denormal + x := u64(exp + (F64_SHIFT + 1) + F64_BIAS) << F64_SHIFT + return f64(1) / (1 << (F64_SHIFT + 1)) * transmute(f64)x + case exp > 1023: // Overflow, +Inf + return 0h7ff00000_00000000 + } + unreachable() +} +pow2_f32 :: proc(#any_int exp: int) -> (res: f32) { + switch { + case exp >= -126 && exp <= 127: // Normal + return transmute(f32)(u32(exp + F32_BIAS) << F32_SHIFT) + case exp < -151: // Underflow + return f32(0) + case exp < -126: // Denormal + x := u32(exp + (F32_SHIFT + 1) + F32_BIAS) << F32_SHIFT + return f32(1) / (1 << (F32_SHIFT + 1)) * transmute(f32)x + case exp > 127: // Overflow, +Inf + return 0h7f80_0000 + } + unreachable() +} + +pow2_f16 :: proc(#any_int exp: int) -> (res: f16) { + switch { + case exp >= -14 && exp <= 15: // Normal + return transmute(f16)(u16(exp + F16_BIAS) << F16_SHIFT) + case exp < -25: // Underflow + return 0h0000 + case exp == -25: // Underflow + return 0h0001 + case exp < -14: // Denormal + x := u16(exp + (F16_SHIFT + 1) + F16_BIAS) << F16_SHIFT + return f16(1) / (1 << (F16_SHIFT + 1)) * transmute(f16)x + case exp > 15: // Overflow, +Inf + return 0h7c00 + } + unreachable() +} @(require_results) ldexp_f64 :: proc "contextless" (val: f64, exp: int) -> f64 { @@ -2302,4 +2349,4 @@ INF_F64 :: f64(0h7FF0_0000_0000_0000) NEG_INF_F64 :: f64(0hFFF0_0000_0000_0000) SNAN_F64 :: f64(0h7FF0_0000_0000_0001) -QNAN_F64 :: f64(0h7FF8_0000_0000_0001) +QNAN_F64 :: f64(0h7FF8_0000_0000_0001) \ No newline at end of file diff --git a/tests/internal/Makefile b/tests/internal/Makefile index 898ba0517..00e46197b 100644 --- a/tests/internal/Makefile +++ b/tests/internal/Makefile @@ -1,9 +1,12 @@ ODIN=../../odin -all: rtti_test map_test +all: rtti_test map_test pow_test rtti_test: $(ODIN) run test_rtti.odin -file -vet -strict-style -o:minimal map_test: - $(ODIN) run test_map.odin -file -vet -strict-style -o:minimal \ No newline at end of file + $(ODIN) run test_map.odin -file -vet -strict-style -o:minimal + +pow_test: + $(ODIN) run test_pow.odin -file -vet -strict-style -o:minimal \ No newline at end of file diff --git a/tests/internal/build.bat b/tests/internal/build.bat index 1f40885bb..f289d17fa 100644 --- a/tests/internal/build.bat +++ b/tests/internal/build.bat @@ -2,4 +2,5 @@ set PATH_TO_ODIN==..\..\odin rem %PATH_TO_ODIN% run test_rtti.odin -file -vet -strict-style -o:minimal || exit /b %PATH_TO_ODIN% run test_map.odin -file -vet -strict-style -o:minimal || exit /b -rem -define:SEED=42 \ No newline at end of file +rem -define:SEED=42 +%PATH_TO_ODIN% run test_pow.odin -file -vet -strict-style -o:minimal || exit /b \ No newline at end of file diff --git a/tests/internal/test_pow.odin b/tests/internal/test_pow.odin new file mode 100644 index 000000000..b169e1361 --- /dev/null +++ b/tests/internal/test_pow.odin @@ -0,0 +1,67 @@ +package test_internal_math_pow + +import "core:fmt" +import "core:math" +import "core:os" +import "core:testing" + +@test +pow_test :: proc(t: ^testing.T) { + for exp in -2000..=2000 { + { + v1 := math.pow(2, f64(exp)) + v2 := math.pow2_f64(exp) + _v1 := transmute(u64)v1 + _v2 := transmute(u64)v2 + expect(t, _v1 == _v2, fmt.tprintf("Expected math.pow2_f64(%d) == math.pow(2, %d) (= %x), got %x", exp, exp, v1, v2)) + } + { + v1 := math.pow(2, f32(exp)) + v2 := math.pow2_f32(exp) + _v1 := transmute(u32)v1 + _v2 := transmute(u32)v2 + expect(t, _v1 == _v2, fmt.tprintf("Expected math.pow2_f32(%d) == math.pow(2, %d) (= %x), got %x", exp, exp, v1, v2)) + } + { + v1 := math.pow(2, f16(exp)) + v2 := math.pow2_f16(exp) + _v1 := transmute(u16)v1 + _v2 := transmute(u16)v2 + expect(t, _v1 == _v2, fmt.tprintf("Expected math.pow2_f16(%d) == math.pow(2, %d) (= %x), got %x", exp, exp, v1, v2)) + } + } +} + +// -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- + +main :: proc() { + t := testing.T{} + + pow_test(&t) + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } +} + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} \ No newline at end of file From 4cb0edc90b5f6f435502dbe9c820355595af7957 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 4 Nov 2023 22:42:32 +0100 Subject: [PATCH 022/160] Work around LLVM idiocy. --- core/math/math.odin | 5 +++-- tests/internal/test_pow | Bin 0 -> 330048 bytes tests/internal/test_pow.odin | 12 +++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 tests/internal/test_pow diff --git a/core/math/math.odin b/core/math/math.odin index a5d86cffb..0d8873071 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -209,8 +209,9 @@ pow2_f64 :: proc(#any_int exp: int) -> (res: f64) { return transmute(f64)(u64(exp + F64_BIAS) << F64_SHIFT) case exp < -1075: // Underflow return f64(0) - case exp == -1075: // Underflow - return 0h00000000_00000001 + case exp == -1075: // Underflow. + // Note that pow(2, -1075) returns 0h1 on Windows and 0h0 on macOS & Linux. + return 0h00000000_00000000 case exp < -1022: // Denormal x := u64(exp + (F64_SHIFT + 1) + F64_BIAS) << F64_SHIFT return f64(1) / (1 << (F64_SHIFT + 1)) * transmute(f64)x diff --git a/tests/internal/test_pow b/tests/internal/test_pow new file mode 100644 index 0000000000000000000000000000000000000000..00fb4a3d59824d83d9325ad97ff543a09e79c56e GIT binary patch literal 330048 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 Date: Sat, 4 Nov 2023 22:47:59 +0100 Subject: [PATCH 023/160] Delete test artifact. --- tests/internal/test_pow | Bin 330048 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/internal/test_pow diff --git a/tests/internal/test_pow b/tests/internal/test_pow deleted file mode 100644 index 00fb4a3d59824d83d9325ad97ff543a09e79c56e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 330048 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 Date: Sun, 5 Nov 2023 14:58:27 +1100 Subject: [PATCH 024/160] [vendor/raylib]: Add pre-compiled libraries on linux; Minor changes in bindings --- vendor/raylib/linux/libraygui.a | Bin 0 -> 122858 bytes vendor/raylib/linux/libraygui.so.3.6 | Bin 0 -> 90584 bytes vendor/raylib/raygui.odin | 29 ++++++++------------------- 3 files changed, 8 insertions(+), 21 deletions(-) create mode 100644 vendor/raylib/linux/libraygui.a create mode 100755 vendor/raylib/linux/libraygui.so.3.6 diff --git a/vendor/raylib/linux/libraygui.a b/vendor/raylib/linux/libraygui.a new file mode 100644 index 0000000000000000000000000000000000000000..1e0ea9e2f93f156524928299f65a0edabf0673aa GIT binary patch literal 122858 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 z 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 l8+OA23Mv5+g>o1e7(m0w*z{{hK~%m)C c.int --- // Label control, shows text - GuiButton :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Button control, returns true when clicked - GuiLabelButton :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Label button control, show true when clicked + GuiButton :: proc(bounds: Rectangle, text: cstring) -> bool --- // Button control, returns true when clicked + GuiLabelButton :: proc(bounds: Rectangle, text: cstring) -> bool --- // Label button control, show true when clicked GuiToggle :: proc(bounds: Rectangle, text: cstring, active: ^bool) -> c.int --- // Toggle Button control, returns true when active GuiToggleGroup :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Toggle Group control, returns active toggle index - GuiCheckBox :: proc(bounds: Rectangle, text: cstring, checked: ^bool) -> c.int --- // Check Box control, returns true when active + GuiCheckBox :: proc(bounds: Rectangle, text: cstring, checked: ^bool) -> bool --- // Check Box control, returns true when active GuiComboBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Combo Box control, returns selected item index - GuiDropdownBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int, editMode: bool) -> c.int --- // Dropdown Box control, returns selected item + GuiDropdownBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int, editMode: bool) -> bool --- // Dropdown Box control, returns selected item GuiSpinner :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Spinner control, returns selected value GuiValueBox :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Value Box control, updates input text with numbers - GuiTextBox :: proc(bounds: Rectangle, text: cstring, textSize: c.int, editMode: bool) -> c.int --- // Text Box control, updates input text + GuiTextBox :: proc(bounds: Rectangle, text: cstring, textSize: c.int, editMode: bool) -> bool --- // Text Box control, updates input text GuiSlider :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider control, returns selected value GuiSliderBar :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider Bar control, returns selected value From 764ce2a4b0259da1df23430e8baae96d4d31a0b8 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 6 Nov 2023 14:58:34 +0100 Subject: [PATCH 025/160] RAYLIB_SHARED: use /NODEFAULTLIB:msvcrt instead of /NODEFAULTLIB:libcmt. This fixes linker errors. --- vendor/raylib/raylib.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 69a5959f8..aa67fd906 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -99,7 +99,7 @@ RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) when ODIN_OS == .Windows { when RAYLIB_SHARED { - @(extra_linker_flags="/NODEFAULTLIB:libcmt") + @(extra_linker_flags="/NODEFAULTLIB:msvcrt") foreign import lib { "windows/raylibdll.lib", "system:Winmm.lib", From c36ac4bdfd2c8bb2f1dfd011f7b413d4b06dfa77 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 6 Nov 2023 13:59:06 +0000 Subject: [PATCH 026/160] Bodge: fix matrix_flatten issue in Win64 ABI --- src/llvm_backend_expr.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 3455bedff..8678a125c 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -684,7 +684,8 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - if (lb_is_matrix_simdable(mt)) { + // TODO(bill): Determine why this fails on Windows sometimes + if (false && lb_is_matrix_simdable(mt)) { LLVMValueRef vector = lb_matrix_to_trimmed_vector(p, m); return lb_matrix_cast_vector_to_type(p, vector, type); } @@ -693,13 +694,29 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type i64 row_count = mt->Matrix.row_count; i64 column_count = mt->Matrix.column_count; + TEMPORARY_ALLOCATOR_GUARD(); + + auto srcs = array_make(temporary_allocator(), 0, row_count*column_count); + auto dsts = array_make(temporary_allocator(), 0, row_count*column_count); + for (i64 j = 0; j < column_count; j++) { for (i64 i = 0; i < row_count; i++) { lbValue src = lb_emit_matrix_ev(p, m, i, j); - lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count); - lb_emit_store(p, dst, src); + array_add(&srcs, src); } } + + for (i64 j = 0; j < column_count; j++) { + for (i64 i = 0; i < row_count; i++) { + lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count); + array_add(&dsts, dst); + } + } + + GB_ASSERT(srcs.count == dsts.count); + for_array(i, srcs) { + lb_emit_store(p, dsts[i], srcs[i]); + } return lb_addr_load(p, res); } From 51229a29f8c7e6b10cb99ee0363a4e2f29df40b6 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 6 Nov 2023 15:20:41 +0100 Subject: [PATCH 027/160] Raylib: use fixed array instead of struct for rl.Color. This makes swizzling etc work, but the memory layout is still the same --- vendor/raylib/raylib.odin | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index aa67fd906..21d044145 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -245,12 +245,9 @@ when USE_LINALG { } // Color, 4 components, R8G8B8A8 (32bit) -Color :: struct { - r: u8, // Color red value - g: u8, // Color green value - b: u8, // Color blue value - a: u8, // Color alpha value -} +// +// Note: In Raylib this is a struct. But here we use a fixed array, so that .rgba swizzling etc work. +Color :: distinct [4]u8 // Rectangle type Rectangle :: struct { From c20839c461bfe8986f5a7f9594fdd13a7845b24b Mon Sep 17 00:00:00 2001 From: Divan Burger Date: Mon, 6 Nov 2023 23:08:36 +0200 Subject: [PATCH 028/160] Fix use of unitialized socket in socket_linux.odin#_dial_tcp_from_endpoint --- core/net/socket_linux.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index 590946dff..539317141 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -143,7 +143,7 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio reuse_addr: b32 = true _ = linux.setsockopt(os_sock, linux.SOL_SOCKET, linux.Socket_Option.REUSEADDR, &reuse_addr) addr := _unwrap_os_addr(endpoint) - errno = linux.connect(linux.Fd(tcp_sock), &addr) + errno = linux.connect(linux.Fd(os_sock), &addr) if errno != .NONE { return cast(TCP_Socket) os_sock, Dial_Error(errno) } From 8714fd77a0635eb6804c048372a346487ba9af32 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 6 Nov 2023 22:24:02 +0100 Subject: [PATCH 029/160] Temporarily disable vendor tests on macOS (botan) --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60e3e94d2..aacaf427d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,11 +87,6 @@ jobs: cd tests/core make timeout-minutes: 10 - - name: Vendor library tests - run: | - cd tests/vendor - make - timeout-minutes: 10 - name: Odin internals tests run: | cd tests/internal From e2cecafa66e6445e96e63cd2ee70bd03735eb83d Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 7 Nov 2023 21:09:42 +0100 Subject: [PATCH 030/160] allow integer verbs in fmt_bit_set --- core/fmt/fmt.odin | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index f0d70e415..402f783cf 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1534,8 +1534,9 @@ stored_enum_value_to_string :: proc(enum_type: ^runtime.Type_Info, ev: runtime.T // - fi: A pointer to the Info structure where the formatted bit set will be written. // - v: The bit set value to be formatted. // - name: An optional string for the name of the bit set (default is an empty string). +// - verb: An optional verb to adjust format. // -fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { +fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') { is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { if ti == nil { return false @@ -1559,7 +1560,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { case runtime.Type_Info_Named: val := v val.id = info.base.id - fmt_bit_set(fi, val, info.name) + fmt_bit_set(fi, val, info.name, verb) case runtime.Type_Info_Bit_Set: bits: u128 @@ -1567,26 +1568,52 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying) + as_arg := verb == 'b' || verb == 'o' || verb == 'd' || verb == 'i' || verb == 'z' || verb == 'x' || verb == 'X' + if as_arg && !fi.width_set { + fi.width_set = true + fi.width = int(bit_size) + } + switch bit_size { case 0: bits = 0 case 8: x := (^u8)(v.data)^ + if as_arg { + fmt_arg(fi, x, verb) + return + } bits = u128(x) case 16: x := (^u16)(v.data)^ if do_byte_swap { x = byte_swap(x) } + if as_arg { + fmt_arg(fi, x, verb) + return + } bits = u128(x) case 32: x := (^u32)(v.data)^ if do_byte_swap { x = byte_swap(x) } + if as_arg { + fmt_arg(fi, x, verb) + return + } bits = u128(x) case 64: x := (^u64)(v.data)^ if do_byte_swap { x = byte_swap(x) } + if as_arg { + fmt_arg(fi, x, verb) + return + } bits = u128(x) case 128: x := (^u128)(v.data)^ if do_byte_swap { x = byte_swap(x) } + if as_arg { + fmt_arg(fi, x, verb) + return + } bits = x case: panic("unknown bit_size size") } @@ -1628,6 +1655,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { } } } + // Writes the specified number of indents to the provided Info structure // // Inputs: @@ -2173,7 +2201,7 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named) case runtime.Type_Info_Struct: fmt_struct(fi, v, verb, b, info.name) case runtime.Type_Info_Bit_Set: - fmt_bit_set(fi, v) + fmt_bit_set(fi, v, verb = verb) case: fmt_value(fi, any{v.data, info.base.id}, verb) } @@ -2594,7 +2622,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { reflect.write_typeid(fi.writer, id, &fi.n) case runtime.Type_Info_Bit_Set: - fmt_bit_set(fi, v) + fmt_bit_set(fi, v, verb = verb) case runtime.Type_Info_Relative_Pointer: ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id) From 4266a7c1664d1f736d270b5eb0c7a9bc31cfe700 Mon Sep 17 00:00:00 2001 From: flga Date: Tue, 7 Nov 2023 23:19:14 +0000 Subject: [PATCH 031/160] sys/linux: munmap was not using the correct syscall --- core/sys/linux/sys.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index dfb25e5dd..314591d06 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -161,7 +161,7 @@ mprotect :: proc "contextless" (addr: rawptr, size: uint, prot: Mem_Protection) /// Unmap memory /// Available since Linux 1.0 munmap :: proc "contextless" (addr: rawptr, size: uint) -> (Errno) { - ret := syscall(SYS_mmap, addr, size) + ret := syscall(SYS_munmap, addr, size) return Errno(-ret) } From fc6edf65d7dfb24265eff84c22f3dd097e6569d6 Mon Sep 17 00:00:00 2001 From: Laytan Date: Thu, 9 Nov 2023 14:17:22 +0100 Subject: [PATCH 032/160] fix linux.accept, addrlen should be a pointer to the length instead of the length itself --- core/sys/linux/sys.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index 314591d06..e0e19056a 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -331,7 +331,8 @@ where T == Sock_Addr_In6 || T == Sock_Addr_Any { - ret := syscall(SYS_accept4, sock, addr, size_of(T), transmute(int) sockflags) + addr_len: i32 = size_of(T) + ret := syscall(SYS_accept4, sock, addr, &addr_len, transmute(int) sockflags) return errno_unwrap(ret, Fd) } From 761a079789e813cfed3a3223e05f66152bfd3a9d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 9 Nov 2023 16:56:54 +0100 Subject: [PATCH 033/160] Fix net.split_url Resolves issue #2924 --- core/net/url.odin | 2 +- tests/core/net/test_core_net.odin | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/net/url.odin b/core/net/url.odin index ef43d6c9f..53c94d863 100644 --- a/core/net/url.odin +++ b/core/net/url.odin @@ -24,7 +24,7 @@ import "core:encoding/hex" split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) { s := url - i := strings.last_index(s, "://") + i := strings.index(s, "://") if i >= 0 { scheme = s[:i] s = s[i+3:] diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin index ab5f2e117..5326e5023 100644 --- a/tests/core/net/test_core_net.odin +++ b/tests/core/net/test_core_net.odin @@ -572,6 +572,11 @@ split_url_test :: proc(t: ^testing.T) { {"a" = "", "b" = ""}, {"http://example.com/example?a&b"}, }, + { + "https", "example.com", "/callback", + {"redirect" = "https://other.com/login"}, + {"https://example.com/callback?redirect=https://other.com/login"}, + }, } for test in test_cases { From 6de2b7700fc646f67668febd814a8712a50b609e Mon Sep 17 00:00:00 2001 From: flga Date: Fri, 10 Nov 2023 12:58:53 +0000 Subject: [PATCH 034/160] core:sys/linux: make Perf_Read_Format a bitset --- core/sys/linux/bits.odin | 2 +- core/sys/linux/types.odin | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin index 0cf90ed3b..1ca60d494 100644 --- a/core/sys/linux/bits.odin +++ b/core/sys/linux/bits.odin @@ -718,7 +718,7 @@ Perf_Event_Sample_Type_Bits :: enum { } /// Describes field sets to include in mmaped page -Perf_Read_Format :: enum { +Perf_Read_Format_Bits :: enum { TOTAL_TIME_ENABLED = 0, TOTAL_TIME_RUNNING = 1, ID = 2, diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 8789ca2d1..308b77aee 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -282,6 +282,7 @@ Get_Random_Flags :: bit_set[Get_Random_Flags_Bits; i32] Perf_Flags :: bit_set[Perf_Flags_Bits; uint] Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64] +Perf_Read_Format_Flags :: distinct bit_set[Perf_Read_Format_Bits; u64] Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64] @@ -305,7 +306,7 @@ Perf_Event_Attr :: struct #packed { frequency: u64, }, sample_type: Perf_Event_Sample_Type, - read_format: Perf_Read_Format, + read_format: Perf_Read_Format_Flags, flags: Perf_Event_Flags, wakeup: struct #raw_union { events: u32, From e19460cbd7c847bd5452b2c7bf96b38d06b2a182 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 10 Nov 2023 19:37:08 +0100 Subject: [PATCH 035/160] Add -microarch:? --- build.bat | 1 + src/build_settings.cpp | 19 +++++++++++++++++-- src/llvm_backend.cpp | 7 +++++++ src/main.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/string.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/build.bat b/build.bat index b0ebfe634..41e32f5ed 100644 --- a/build.bat +++ b/build.bat @@ -110,6 +110,7 @@ if %errorlevel% neq 0 goto end_of_build call build_vendor.bat if %errorlevel% neq 0 goto end_of_build +rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native if %release_mode% EQU 0 odin run examples/demo del *.obj > NUL 2> NUL diff --git a/src/build_settings.cpp b/src/build_settings.cpp index ffb276d1e..b9b591a7f 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -82,6 +82,23 @@ gb_global String target_arch_names[TargetArch_COUNT] = { str_lit("wasm64p32"), }; +gb_global String target_microarch_list[TargetArch_COUNT] = { + // TargetArch_Invalid, + str_lit("Invalid!"), + // TargetArch_amd64, + str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2 (default),x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"), + // TargetArch_i386, + str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic (default),geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"), + // TargetArch_arm32, + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic (default),iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + // TargetArch_arm64, + str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic (default),kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + // TargetArch_wasm32, + str_lit("generic (default)"), + // TargetArch_wasm64p32, + str_lit("generic (default)"), +}; + gb_global String target_endian_names[TargetEndian_COUNT] = { str_lit("little"), str_lit("big"), @@ -109,8 +126,6 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = { gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW); - - struct TargetMetrics { TargetOsKind os; TargetArchKind arch; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 276abc2d4..707ef2969 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2518,6 +2518,13 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } + // NOTE(Jeroen): Uncomment to get the list of supported microarchitectures. + /* + if (build_context.microarch == "?") { + string_set_add(&build_context.target_features_set, str_lit("+cpuhelp")); + } + */ + if (build_context.target_features_set.entries.count != 0) { llvm_features = target_features_set_to_cstring(permanent_allocator(), false); } diff --git a/src/main.cpp b/src/main.cpp index 79c2b3561..8a917090b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2518,6 +2518,45 @@ int main(int arg_count, char const **arg_ptr) { // return 1; // } + // Check chosen microarchitecture. If not found or ?, print list. + bool print_microarch_list = true; + if (build_context.microarch.len == 0) { + // Autodetect, no need to print list. + print_microarch_list = false; + } else { + String march_list = target_microarch_list[build_context.metrics.arch]; + String_Iterator it = {march_list, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + // If it's the entry in the list marked (default), we strip off the suffix before the match. + if (string_ends_with(str, str_lit(" (default)"))) { + str = substring(str, 0, str.len - 10); + } + if (str == build_context.microarch) { + // Found matching microarch + print_microarch_list = false; + } + } + } + + if (print_microarch_list) { + if (build_context.microarch != "?") { + gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch)); + } + gb_printf("Possible -microarch values for target %.*s are:\n", LIT(target_arch_names[build_context.metrics.arch])); + gb_printf("\n"); + + String march_list = target_microarch_list[build_context.metrics.arch]; + String_Iterator it = {march_list, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + gb_printf("\t%.*s\n", LIT(str)); + } + return 0; + } + // Set and check build paths... if (!init_build_paths(init_filename)) { return 1; diff --git a/src/string.cpp b/src/string.cpp index 6eac4f53b..e85787c59 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -10,6 +10,10 @@ struct String { return text[i]; } }; +struct String_Iterator { + String const &str; + isize pos; +}; // NOTE(bill): used for printf style arguments #define LIT(x) ((int)(x).len), (x).text #if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700 @@ -201,6 +205,26 @@ gb_internal gb_inline String string_trim_starts_with(String const &s, String con } +gb_internal String string_split_iterator(String_Iterator *it, const char sep) { + isize start = it->pos; + isize end = it->str.len; + + if (start == end) { + return str_lit(""); + } + + isize i = start; + for (; i < it->str.len; i++) { + if (it->str[i] == sep) { + String res = substring(it->str, start, i); + it->pos += res.len + 1; + return res; + } + } + it->pos = end; + return substring(it->str, start, end); +} + gb_internal gb_inline isize string_extension_position(String const &str) { isize dot_pos = -1; isize i = str.len; From f9039510167c50e0a86e4c25fad5aa08aca24bf0 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 10 Nov 2023 20:14:00 +0100 Subject: [PATCH 036/160] Facored out `get_default_microarchitecture` Moved `generic` -> `x86-64-v2` selection into its own procedure so that `llvm_backend.cpp` and `main.cpp` can share the same logic. --- src/build_settings.cpp | 13 ++++++------- src/llvm_backend.cpp | 35 ++++++++++++++++++++--------------- src/main.cpp | 15 +++++++++------ 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b9b591a7f..94807a852 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -86,17 +86,17 @@ gb_global String target_microarch_list[TargetArch_COUNT] = { // TargetArch_Invalid, str_lit("Invalid!"), // TargetArch_amd64, - str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2 (default),x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"), + str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"), // TargetArch_i386, - str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic (default),geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"), + str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic,geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"), // TargetArch_arm32, - str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic (default),iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), // TargetArch_arm64, - str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic (default),kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic,kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), // TargetArch_wasm32, - str_lit("generic (default)"), + str_lit("generic"), // TargetArch_wasm64p32, - str_lit("generic (default)"), + str_lit("generic"), }; gb_global String target_endian_names[TargetEndian_COUNT] = { @@ -638,7 +638,6 @@ gb_internal TargetArchKind get_target_arch_from_string(String str) { return TargetArch_Invalid; } - gb_internal bool is_excluded_target_filename(String name) { String original_name = name; name = remove_extension_from_path(name); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 707ef2969..effd9d28e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -21,6 +21,25 @@ #include "llvm_backend_stmt.cpp" #include "llvm_backend_proc.cpp" +char *get_default_microarchitecture() { + char * default_march = "generic"; + if (build_context.metrics.arch == TargetArch_amd64) { + // NOTE(bill): x86-64-v2 is more than enough for everyone + // + // x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2 + // x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 + // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE + // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL + if (ODIN_LLVM_MINIMUM_VERSION_12) { + if (build_context.metrics.os == TargetOs_freestanding) { + default_march = "x86-64"; + } else { + default_march = "x86-64-v2"; + } + } + } + return default_march; +} gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e) { if (e == nullptr) { @@ -2491,7 +2510,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } char const *host_cpu_name = LLVMGetHostCPUName(); - char const *llvm_cpu = "generic"; + char const *llvm_cpu = get_default_microarchitecture(); char const *llvm_features = ""; if (build_context.microarch.len != 0) { if (build_context.microarch == "native") { @@ -2502,20 +2521,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) { llvm_features = LLVMGetHostCPUFeatures(); } - } else if (build_context.metrics.arch == TargetArch_amd64) { - // NOTE(bill): x86-64-v2 is more than enough for everyone - // - // x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2 - // x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 - // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE - // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL - if (ODIN_LLVM_MINIMUM_VERSION_12) { - if (build_context.metrics.os == TargetOs_freestanding) { - llvm_cpu = "x86-64"; - } else { - llvm_cpu = "x86-64-v2"; - } - } } // NOTE(Jeroen): Uncomment to get the list of supported microarchitectures. diff --git a/src/main.cpp b/src/main.cpp index 8a917090b..bf91a0889 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2529,10 +2529,6 @@ int main(int arg_count, char const **arg_ptr) { for (;;) { String str = string_split_iterator(&it, ','); if (str == "") break; - // If it's the entry in the list marked (default), we strip off the suffix before the match. - if (string_ends_with(str, str_lit(" (default)"))) { - str = substring(str, 0, str.len - 10); - } if (str == build_context.microarch) { // Found matching microarch print_microarch_list = false; @@ -2547,12 +2543,19 @@ int main(int arg_count, char const **arg_ptr) { gb_printf("Possible -microarch values for target %.*s are:\n", LIT(target_arch_names[build_context.metrics.arch])); gb_printf("\n"); - String march_list = target_microarch_list[build_context.metrics.arch]; + String march_list = target_microarch_list[build_context.metrics.arch]; String_Iterator it = {march_list, 0}; + + String default_march = make_string_c(get_default_microarchitecture()); + for (;;) { String str = string_split_iterator(&it, ','); if (str == "") break; - gb_printf("\t%.*s\n", LIT(str)); + if (str == default_march) { + gb_printf("\t%.*s (default)\n", LIT(str)); + } else { + gb_printf("\t%.*s\n", LIT(str)); + } } return 0; } From f6f4734fee4fb253bc7c16410790e97955a72a1e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 10 Nov 2023 20:22:20 +0100 Subject: [PATCH 037/160] Re-add `break`. --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index bf91a0889..59bed1e54 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2532,6 +2532,7 @@ int main(int arg_count, char const **arg_ptr) { if (str == build_context.microarch) { // Found matching microarch print_microarch_list = false; + break; } } } From 5a8da5dcdb36e3ef37853ba571b84603c7bd9f96 Mon Sep 17 00:00:00 2001 From: flga Date: Fri, 10 Nov 2023 19:41:01 +0000 Subject: [PATCH 038/160] core:sys/linux: rename Perf_Read_Format_Flags --- core/sys/linux/types.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 308b77aee..afa7faf33 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -282,7 +282,8 @@ Get_Random_Flags :: bit_set[Get_Random_Flags_Bits; i32] Perf_Flags :: bit_set[Perf_Flags_Bits; uint] Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64] -Perf_Read_Format_Flags :: distinct bit_set[Perf_Read_Format_Bits; u64] + +Perf_Read_Format :: distinct bit_set[Perf_Read_Format_Bits; u64] Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64] @@ -306,7 +307,7 @@ Perf_Event_Attr :: struct #packed { frequency: u64, }, sample_type: Perf_Event_Sample_Type, - read_format: Perf_Read_Format_Flags, + read_format: Perf_Read_Format, flags: Perf_Event_Flags, wakeup: struct #raw_union { events: u32, From 086478e8f20ac9633daaf2e3485ef7778ee82441 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 11 Nov 2023 02:34:59 +0100 Subject: [PATCH 039/160] fix -test-name flag --- src/checker.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index 29f22bd9c..9653116cf 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -6091,9 +6091,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("calculate global init order"); calculate_global_init_order(c); - TIME_SECTION("check test procedures"); - check_test_procedures(c); - TIME_SECTION("add type info for type definitions"); add_type_info_for_type_definitions(c); check_merge_queues_into_arrays(c); @@ -6104,6 +6101,11 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("generate minimum dependency set"); generate_minimum_dependency_set(c, c->info.entry_point); + // NOTE(laytan): has to be ran after generate_minimum_dependency_set, + // because that collects the test procedures. + TIME_SECTION("check test procedures"); + check_test_procedures(c); + TIME_SECTION("check bodies have all been checked"); check_unchecked_bodies(c); From e67473d89a5cd9284d26e7b8a4bfc826c7082668 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sat, 11 Nov 2023 20:20:40 +1100 Subject: [PATCH 040/160] [vendor/x11]: Add most of the basic xlib bindings --- examples/all/all_vendor.odin | 6 +- vendor/x11/.gitignore | 4 + vendor/x11/xlib/xlib_const.odin | 526 ++++++++++ vendor/x11/xlib/xlib_keysym.odin | 1681 ++++++++++++++++++++++++++++++ vendor/x11/xlib/xlib_procs.odin | 1549 +++++++++++++++++++++++++++ vendor/x11/xlib/xlib_types.odin | 1307 +++++++++++++++++++++++ 6 files changed, 5072 insertions(+), 1 deletion(-) create mode 100644 vendor/x11/.gitignore create mode 100644 vendor/x11/xlib/xlib_const.odin create mode 100644 vendor/x11/xlib/xlib_keysym.odin create mode 100644 vendor/x11/xlib/xlib_procs.odin create mode 100644 vendor/x11/xlib/xlib_types.odin diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 6864a7be2..76dd9903a 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -46,6 +46,8 @@ import nvg "vendor:nanovg" import nvg_gl "vendor:nanovg/gl" import fontstash "vendor:fontstash" +import x11 "vendor:x11" + _ :: botan_bindings _ :: botan_blake2b _ :: gost @@ -90,4 +92,6 @@ _ :: lua_5_4 _ :: nvg _ :: nvg_gl -_ :: fontstash \ No newline at end of file +_ :: fontstash + +_ :: x11 \ No newline at end of file diff --git a/vendor/x11/.gitignore b/vendor/x11/.gitignore new file mode 100644 index 000000000..3657af3a4 --- /dev/null +++ b/vendor/x11/.gitignore @@ -0,0 +1,4 @@ + +# TODO(flysand): Remove this file. + +*.i diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin new file mode 100644 index 000000000..b925ec27e --- /dev/null +++ b/vendor/x11/xlib/xlib_const.odin @@ -0,0 +1,526 @@ + +package xlib + +// Special values for many types. Most of these constants +// aren't attached to a specific type. + +None :: 0 +ParentRelative :: 1 +CopyFromParent :: 0 +PointerWindow :: 0 +InputFocus :: 1 +PointerRoot :: 1 +AnyPropertyType :: 0 +AnyKey :: 0 +AnyButton :: 0 +AllTemporary :: 0 +CurrentTime :: 0 +NoSymbol :: 0 + +// NOTE(flysand): Some implementations return Status as enum, other return it +// as an integer. I will make it a status. +Status :: enum i32 { + Success = 0, + BadRequest = 1, + BadValue = 2, + BadWindow = 3, + BadPixmap = 4, + BadAtom = 5, + BadCursor = 6, + BadFont = 7, + BadMatch = 8, + BadDrawable = 9, + BadAccess = 10, + BadAlloc = 11, + BadColor = 12, + BadGC = 13, + BadIDChoice = 14, + BadName = 15, + BadLength = 16, + BadImplementation = 17, + FirstExtensionError = 128, + LastExtensionError = 255, +} + +ByteOrder :: enum i32 { + LSBFirst = 0, + MSBFirst = 1, +} + +Gravity :: enum i32 { + ForgetGravity = 0, + UnmapGravity = 0, + NorthWestGravity = 1, + NorthGravity = 2, + NorthEastGravity = 3, + WestGravity = 4, + CenterGravity = 5, + EastGravity = 6, + SouthWestGravity = 7, + SouthGravity = 8, + SouthEastGravity = 9, + StaticGravity = 10, +} + +BackingStore :: enum i32 { + NotUseful = 0, + WhenMapped = 1, + Always = 2, +} + +EventMask :: bit_set[EventType; int] +EventType :: enum i32 { + KeyPress = 0, + KeyRelease = 1, + ButtonPress = 2, + ButtonRelease = 3, + EnterWindow = 4, + LeaveWindow = 5, + PointerMotion = 6, + PointerMotionHint = 7, + Button1Motion = 8, + Button2Motion = 9, + Button3Motion = 10, + Button4Motion = 11, + Button5Motion = 12, + ButtonMotion = 13, + KeymapState = 14, + Exposure = 15, + VisibilityChange = 16, + StructureNotify = 17, + ResizeRedirect = 18, + SubstructureNotify = 19, + SubstructureRedirect = 20, + FocusChange = 21, + PropertyChange = 22, + ColormapChange = 23, + OwnerGrabButton = 24, +} + +InputMask :: bit_set[InputMaskBits; i32] +InputMaskBits :: enum { + ShiftMask = 0, + LockMask = 1, + ControlMask = 2, + Mod1Mask = 3, + Mod2Mask = 4, + Mod3Mask = 5, + Mod4Mask = 6, + Mod5Mask = 7, + Button1Mask = 8, + Button2Mask = 9, + Button3Mask = 10, + Button4Mask = 11, + Button5Mask = 12, + AnyModifier = 15, +} + +NotifyMode :: enum i32 { + NotifyNormal = 0, + NotifyGrab = 1, + NotifyUngrab = 2, + NotifyWhileGrabbed = 3, +} + +NotifyDetail :: enum i32 { + NotifyAncestor = 0, + NotifyVirtual = 1, + NotifyInferior = 2, + NotifyNonlinear = 3, + NotifyNonlinearVirtual = 4, + NotifyPointer = 5, + NotifyPointerRoot = 6, + NotifyDetailNone = 7, +} + +MappingRequest :: enum i32 { + MappingModifier = 0, + MappingKeyboard = 1, + MappingPointer = 2, +} + +VisibilityState :: enum i32 { + VisibilityUnobscured = 0, + VisibilityPartiallyObscured = 1, + VisibilityFullyObscured = 2, +} + +ColormapState :: enum i32 { + ColormapUninstalled = 0, + ColormapInstalled = 1, +} + +PropertyState :: enum i32 { + PropertyNewValue = 0, + PropertyDelete = 1, +} + +CloseMode :: enum i32 { + DestroyAll = 0, + RetainPermanent = 1, + RetainTemporary = 2, +} + +EventQueueMode :: enum i32 { + QueuedAlready = 0, + QueuedAfterReading = 1, + QueuedAfterFlush = 2, +} + +WindowAttributeMask :: bit_set[WindowAttributeMaskBits; int] +WindowAttributeMaskBits :: enum { + CWBackPixmap = 0, + CWBackPixel = 1, + CWBorderPixmap = 2, + CWBorderPixel = 3, + CWBitGravity = 4, + CWWinGravity = 5, + CWBackingStore = 6, + CWBackingPlanes = 7, + CWBackingPixel = 8, + CWOverrideRedirect = 9, + CWSaveUnder = 10, + CWEventMask = 11, + CWDontPropagate = 12, + CWColormap = 13, + CWCursor = 14, +} + +WindowClass :: enum i32 { + CopyFromParent = 0, + InputOutput = 1, + InputOnly = 2, +} + +WindowChangesMask :: bit_set[WindowChangesMaskBits; i32] +WindowChangesMaskBits :: enum { + CWX = 0, + CWY = 1, + CWWidth = 2, + CWHeight = 3, + CWBorderWidth = 4, + CWSibling = 5, + CWStackMode = 6, +} + +WindowStacking :: enum i32 { + Above = 0, + Below = 1, + TopIf = 2, + BottomIf = 3, + Opposite = 4, +} + +CirculationDirection :: enum i32 { + RaiseLowest = 0, + LowerHighest = 1, +} + +CirculationRequest :: enum i32 { + PlaceOnTop = 0, + PlaceOnBottom = 1, +} + +WindowMapState :: enum i32 { + IsUnmapped = 0, + IsUnviewable = 1, + IsViewable = 2, +} + +KeyMask :: enum u32 { + ShiftMask = 0, + LockMask = 1, + ControlMask = 2, + Mod1Mask = 3, + Mod2Mask = 4, + Mod3Mask = 5, + Mod4Mask = 6, + Mod5Mask = 7, +} + +CursorShape :: enum u32 { + XC_X_cursor = 0, + XC_arrow = 2, + XC_based_arrow_down = 4, + XC_based_arrow_up = 6, + XC_boat = 8, + XC_bogosity = 10, + XC_bottom_left_corner = 12, + XC_bottom_right_corner = 14, + XC_bottom_side = 16, + XC_bottom_tee = 18, + XC_box_spiral = 20, + XC_center_ptr = 22, + XC_circle = 24, + XC_clock = 26, + XC_coffee_mug = 28, + XC_cross = 30, + XC_cross_reverse = 32, + XC_crosshair = 34, + XC_diamond_cross = 36, + XC_dot = 38, + XC_dotbox = 40, + XC_double_arrow = 42, + XC_draft_large = 44, + XC_draft_small = 46, + XC_draped_box = 48, + XC_exchange = 50, + XC_fleur = 52, + XC_gobbler = 54, + XC_gumby = 56, + XC_hand1 = 58, + XC_hand2 = 60, + XC_heart = 62, + XC_icon = 64, + XC_iron_cross = 66, + XC_left_ptr = 68, + XC_left_side = 70, + XC_left_tee = 72, + XC_leftbutton = 74, + XC_ll_angle = 76, + XC_lr_angle = 78, + XC_man = 80, + XC_middlebutton = 82, + XC_mouse = 84, + XC_pencil = 86, + XC_pirate = 88, + XC_plus = 90, + XC_question_arrow = 92, + XC_right_ptr = 94, + XC_right_side = 96, + XC_right_tee = 98, + XC_rightbutton = 100, + XC_rtl_logo = 102, + XC_sailboat = 104, + XC_sb_down_arrow = 106, + XC_sb_h_double_arrow = 108, + XC_sb_left_arrow = 110, + XC_sb_right_arrow = 112, + XC_sb_up_arrow = 114, + XC_sb_v_double_arrow = 116, + XC_shuttle = 118, + XC_sizing = 120, + XC_spider = 122, + XC_spraycan = 124, + XC_star = 126, + XC_target = 128, + XC_tcross = 130, + XC_top_left_arrow = 132, + XC_top_left_corner = 134, + XC_top_right_corner = 136, + XC_top_side = 138, + XC_top_tee = 140, + XC_trek = 142, + XC_ul_angle = 144, + XC_umbrella = 146, + XC_ur_angle = 148, + XC_watch = 150, + XC_xterm = 152, + XC_num_glyphs = 154, +} + +ColorFormat :: enum u32 { + XcmsUndefinedFormat = 0x00000000, + XcmsCIEXYZFormat = 0x00000001, + XcmsCIEuvYFormat = 0x00000002, + XcmsCIExyYFormat = 0x00000003, + XcmsCIELabFormat = 0x00000004, + XcmsCIELuvFormat = 0x00000005, + XcmsTekHVCFormat = 0x00000006, + XcmsRGBFormat = 0x80000000, + XcmsRGBiFormat = 0x80000001, +} + +ColormapAlloc :: enum i32 { + AllocNone = 0, + AllocAll = 1, +} + +ColorFlags :: bit_set[ColorFlagsBits; i32] +ColorFlagsBits :: enum { + DoRed = 0, + DoGreen = 1, + DoBlue = 2, +} + +GCAttributeMask :: bit_set[GCAttributeMaskBits; uint] +GCAttributeMaskBits :: enum { + GCFunction = 0, + GCPlaneMask = 1, + GCForeground = 2, + GCBackground = 3, + GCLineWidth = 4, + GCLineStyle = 5, + GCCapStyle = 6, + GCJoinStyle = 7, + GCFillStyle = 8, + GCFillRule = 9, + GCTile = 10, + GCStipple = 11, + GCTileStipXOrigin = 12, + GCTileStipYOrigin = 13, + GCFont = 14, + GCSubwindowMode = 15, + GCGraphicsExposures= 16, + GCClipXOrigin = 17, + GCClipYOrigin = 18, + GCClipMask = 19, + GCDashOffset = 20, + GCDashList = 21, + GCArcMode = 22, +} + +GCFunction :: enum i32 { + GXclear = 0x0, // 0 + GXand = 0x1, // src & dst + GXandReverse = 0x2, // src & ~dst + GXcopy = 0x3, // src + GXandInverted = 0x4, // ~src & dst + GXnoop = 0x5, // dst + GXxor = 0x6, // src ~ dst + GXor = 0x7, // src | dst + GXnor = 0x8, // ~src & ~dst + GXequiv = 0x9, // ~src ~ dst + GXinvert = 0xa, // ~dst + GXorReverse = 0xb, // src | ~dst + GXcopyInverted = 0xc, // ~src + GXorInverted = 0xd, // ~src | dst + GXnand = 0xe, // ~src | ~dst + GXset = 0xf, // 1 +} + +LineStyle :: enum i32 { + LineSolid = 0, + LineOnOffDash = 1, + LineDoubleDash = 2, +} + +CapStyle :: enum i32 { + CapNotLast = 0, + CapButt = 1, + CapRound = 2, + CapProjecting = 3, +} + +JoinStyle :: enum i32 { + JoinMiter = 0, + JoinRound = 1, + JoinBevel = 2, +} + +FillStyle :: enum i32 { + FillSolid = 0, + FillTiled = 1, + FillStippled = 2, + FillOpaqueStippled = 3, +} + +FillRule :: enum i32 { + EvenOddRule = 0, + WindingRule = 1, +} + +ArcMode :: enum i32 { + ArcChord = 0, + ArcPieSlice = 1, +} + +SubwindowMode :: enum i32 { + ClipByChildren = 0, + IncludeInferiors = 1, +} + +CoordMode :: enum i32 { + CoordModeOrigin = 0, + CoordModePrevious = 1, +} + +Shape :: enum i32 { + Complex = 0, + Nonconvex = 1, + Convex = 2, +} + +FontDirection :: enum i32 { + FontLeftToRight = 0, + FontRightToLeft = 1, +} + +ImageFormat :: enum i32 { + XYBitmap = 0, + XYPixmap = 1, + ZPixmap = 2, +} + +SaveSetChangeMode :: enum i32 { + SetModeInsert = 0, + SetModeDelete = 1, +} + + +ScreenSaverBlanking :: enum i32 { + DontPreferBlanking = 0, + PreferBlanking = 1, + DefaultBlanking = 2, +} + +ScreenSavingExposures :: enum i32 { + DontAllowExposures = 0, + AllowExposures = 1, + DefaultExposures = 2, +} + +ScreenSaverForceMode :: enum i32 { + ScreenSaverReset = 0, + ScreenSaverActive = 1, +} + +AccessControlMode :: enum i32 { + DisableAccess = 0, + EnableAccess = 1, +} + +GrabMode :: enum i32 { + GrabModeSync = 0, + GrabModeAsync = 1, +} + +AllowEventsMode :: enum i32 { + AsyncPointer = 0, + SyncPointer = 1, + ReplayPointer = 2, + AsyncKeyboard = 3, + SyncKeyboard = 4, + ReplayKeyboard = 5, + AsyncBoth = 6, + SyncBoth = 7, +} + +FocusRevert :: enum i32 { + RevertToNone = 0, + RevertToPointerRoot = 1, + RevertToParent = 2, +} + +KeyboardControlMask :: bit_set[KeyboardControlMaskBits; int] +KeyboardControlMaskBits :: enum { + KBKeyClickPercent = 0, + KBBellPercent = 1, + KBBellPitch = 2, + KBBellDuration = 3, + KBLed = 4, + KBLedMode = 5, + KBKey = 6, + KBAutoRepeatMode = 7, +} + +KeyboardAutoRepeatMode :: enum i32 { + AutoRepeatModeOff = 0, + AutoRepeatModeOn = 1, + AutoRepeatModeDefault = 2, +} + +KeyboardLedMode :: enum i32 { + LedModeOff = 0, + LedModeOn = 1, +} diff --git a/vendor/x11/xlib/xlib_keysym.odin b/vendor/x11/xlib/xlib_keysym.odin new file mode 100644 index 000000000..c712bf784 --- /dev/null +++ b/vendor/x11/xlib/xlib_keysym.odin @@ -0,0 +1,1681 @@ + +package xlib + +KeySym :: enum u32 { + XK_BackSpace = 0xff08, /* Back space, back char */ + XK_Tab = 0xff09, + XK_Linefeed = 0xff0a, /* Linefeed, LF */ + XK_Clear = 0xff0b, + XK_Return = 0xff0d, /* Return, enter */ + XK_Pause = 0xff13, /* Pause, hold */ + XK_Scroll_Lock = 0xff14, + XK_Sys_Req = 0xff15, + XK_Escape = 0xff1b, + XK_Delete = 0xffff, /* Delete, rubout */ + XK_Multi_key = 0xff20, /* Multi-key character compose */ + XK_Codeinput = 0xff37, + XK_SingleCandidate = 0xff3c, + XK_MultipleCandidate = 0xff3d, + XK_PreviousCandidate = 0xff3e, + XK_Kanji = 0xff21, /* Kanji, Kanji convert */ + XK_Muhenkan = 0xff22, /* Cancel Conversion */ + XK_Henkan_Mode = 0xff23, /* Start/Stop Conversion */ + XK_Henkan = 0xff23, /* Alias for Henkan_Mode */ + XK_Romaji = 0xff24, /* to Romaji */ + XK_Hiragana = 0xff25, /* to Hiragana */ + XK_Katakana = 0xff26, /* to Katakana */ + XK_Hiragana_Katakana = 0xff27, /* Hiragana/Katakana toggle */ + XK_Zenkaku = 0xff28, /* to Zenkaku */ + XK_Hankaku = 0xff29, /* to Hankaku */ + XK_Zenkaku_Hankaku = 0xff2a, /* Zenkaku/Hankaku toggle */ + XK_Touroku = 0xff2b, /* Add to Dictionary */ + XK_Massyo = 0xff2c, /* Delete from Dictionary */ + XK_Kana_Lock = 0xff2d, /* Kana Lock */ + XK_Kana_Shift = 0xff2e, /* Kana Shift */ + XK_Eisu_Shift = 0xff2f, /* Alphanumeric Shift */ + XK_Eisu_toggle = 0xff30, /* Alphanumeric toggle */ + XK_Kanji_Bangou = 0xff37, /* Codeinput */ + XK_Zen_Koho = 0xff3d, /* Multiple/All Candidate(s) */ + XK_Mae_Koho = 0xff3e, /* Previous Candidate */ + XK_Home = 0xff50, + XK_Left = 0xff51, /* Move left, left arrow */ + XK_Up = 0xff52, /* Move up, up arrow */ + XK_Right = 0xff53, /* Move right, right arrow */ + XK_Down = 0xff54, /* Move down, down arrow */ + XK_Prior = 0xff55, /* Prior, previous */ + XK_Page_Up = 0xff55, + XK_Next = 0xff56, /* Next */ + XK_Page_Down = 0xff56, + XK_End = 0xff57, /* EOL */ + XK_Begin = 0xff58, /* BOL */ + XK_Select = 0xff60, /* Select, mark */ + XK_Print = 0xff61, + XK_Execute = 0xff62, /* Execute, run, do */ + XK_Insert = 0xff63, /* Insert, insert here */ + XK_Undo = 0xff65, + XK_Redo = 0xff66, /* Redo, again */ + XK_Menu = 0xff67, + XK_Find = 0xff68, /* Find, search */ + XK_Cancel = 0xff69, /* Cancel, stop, abort, exit */ + XK_Help = 0xff6a, /* Help */ + XK_Break = 0xff6b, + XK_Mode_switch = 0xff7e, /* Character set switch */ + XK_script_switch = 0xff7e, /* Alias for mode_switch */ + XK_Num_Lock = 0xff7f, + XK_KP_Space = 0xff80, /* Space */ + XK_KP_Tab = 0xff89, + XK_KP_Enter = 0xff8d, /* Enter */ + XK_KP_F1 = 0xff91, /* PF1, KP_A, ... */ + XK_KP_F2 = 0xff92, + XK_KP_F3 = 0xff93, + XK_KP_F4 = 0xff94, + XK_KP_Home = 0xff95, + XK_KP_Left = 0xff96, + XK_KP_Up = 0xff97, + XK_KP_Right = 0xff98, + XK_KP_Down = 0xff99, + XK_KP_Prior = 0xff9a, + XK_KP_Page_Up = 0xff9a, + XK_KP_Next = 0xff9b, + XK_KP_Page_Down = 0xff9b, + XK_KP_End = 0xff9c, + XK_KP_Begin = 0xff9d, + XK_KP_Insert = 0xff9e, + XK_KP_Delete = 0xff9f, + XK_KP_Equal = 0xffbd, /* Equals */ + XK_KP_Multiply = 0xffaa, + XK_KP_Add = 0xffab, + XK_KP_Separator = 0xffac, /* Separator, often comma */ + XK_KP_Subtract = 0xffad, + XK_KP_Decimal = 0xffae, + XK_KP_Divide = 0xffaf, + XK_KP_0 = 0xffb0, + XK_KP_1 = 0xffb1, + XK_KP_2 = 0xffb2, + XK_KP_3 = 0xffb3, + XK_KP_4 = 0xffb4, + XK_KP_5 = 0xffb5, + XK_KP_6 = 0xffb6, + XK_KP_7 = 0xffb7, + XK_KP_8 = 0xffb8, + XK_KP_9 = 0xffb9, + XK_F1 = 0xffbe, + XK_F2 = 0xffbf, + XK_F3 = 0xffc0, + XK_F4 = 0xffc1, + XK_F5 = 0xffc2, + XK_F6 = 0xffc3, + XK_F7 = 0xffc4, + XK_F8 = 0xffc5, + XK_F9 = 0xffc6, + XK_F10 = 0xffc7, + XK_F11 = 0xffc8, + XK_L1 = 0xffc8, + XK_F12 = 0xffc9, + XK_L2 = 0xffc9, + XK_F13 = 0xffca, + XK_L3 = 0xffca, + XK_F14 = 0xffcb, + XK_L4 = 0xffcb, + XK_F15 = 0xffcc, + XK_L5 = 0xffcc, + XK_F16 = 0xffcd, + XK_L6 = 0xffcd, + XK_F17 = 0xffce, + XK_L7 = 0xffce, + XK_F18 = 0xffcf, + XK_L8 = 0xffcf, + XK_F19 = 0xffd0, + XK_L9 = 0xffd0, + XK_F20 = 0xffd1, + XK_L10 = 0xffd1, + XK_F21 = 0xffd2, + XK_R1 = 0xffd2, + XK_F22 = 0xffd3, + XK_R2 = 0xffd3, + XK_F23 = 0xffd4, + XK_R3 = 0xffd4, + XK_F24 = 0xffd5, + XK_R4 = 0xffd5, + XK_F25 = 0xffd6, + XK_R5 = 0xffd6, + XK_F26 = 0xffd7, + XK_R6 = 0xffd7, + XK_F27 = 0xffd8, + XK_R7 = 0xffd8, + XK_F28 = 0xffd9, + XK_R8 = 0xffd9, + XK_F29 = 0xffda, + XK_R9 = 0xffda, + XK_F30 = 0xffdb, + XK_R10 = 0xffdb, + XK_F31 = 0xffdc, + XK_R11 = 0xffdc, + XK_F32 = 0xffdd, + XK_R12 = 0xffdd, + XK_F33 = 0xffde, + XK_R13 = 0xffde, + XK_F34 = 0xffdf, + XK_R14 = 0xffdf, + XK_F35 = 0xffe0, + XK_R15 = 0xffe0, + XK_Shift_L = 0xffe1, /* Left shift */ + XK_Shift_R = 0xffe2, /* Right shift */ + XK_Control_L = 0xffe3, /* Left control */ + XK_Control_R = 0xffe4, /* Right control */ + XK_Caps_Lock = 0xffe5, /* Caps lock */ + XK_Shift_Lock = 0xffe6, /* Shift lock */ + XK_Meta_L = 0xffe7, /* Left meta */ + XK_Meta_R = 0xffe8, /* Right meta */ + XK_Alt_L = 0xffe9, /* Left alt */ + XK_Alt_R = 0xffea, /* Right alt */ + XK_Super_L = 0xffeb, /* Left super */ + XK_Super_R = 0xffec, /* Right super */ + XK_Hyper_L = 0xffed, /* Left hyper */ + XK_Hyper_R = 0xffee, /* Right hyper */ + XK_ISO_Lock = 0xfe01, + XK_ISO_Level2_Latch = 0xfe02, + XK_ISO_Level3_Shift = 0xfe03, + XK_ISO_Level3_Latch = 0xfe04, + XK_ISO_Level3_Lock = 0xfe05, + XK_ISO_Group_Shift = 0xff7e, /* Alias for mode_switch */ + XK_ISO_Group_Latch = 0xfe06, + XK_ISO_Group_Lock = 0xfe07, + XK_ISO_Next_Group = 0xfe08, + XK_ISO_Next_Group_Lock = 0xfe09, + XK_ISO_Prev_Group = 0xfe0a, + XK_ISO_Prev_Group_Lock = 0xfe0b, + XK_ISO_First_Group = 0xfe0c, + XK_ISO_First_Group_Lock = 0xfe0d, + XK_ISO_Last_Group = 0xfe0e, + XK_ISO_Last_Group_Lock = 0xfe0f, + XK_ISO_Left_Tab = 0xfe20, + XK_ISO_Move_Line_Up = 0xfe21, + XK_ISO_Move_Line_Down = 0xfe22, + XK_ISO_Partial_Line_Up = 0xfe23, + XK_ISO_Partial_Line_Down = 0xfe24, + XK_ISO_Partial_Space_Left = 0xfe25, + XK_ISO_Partial_Space_Right = 0xfe26, + XK_ISO_Set_Margin_Left = 0xfe27, + XK_ISO_Set_Margin_Right = 0xfe28, + XK_ISO_Release_Margin_Left = 0xfe29, + XK_ISO_Release_Margin_Right = 0xfe2a, + XK_ISO_Release_Both_Margins = 0xfe2b, + XK_ISO_Fast_Cursor_Left = 0xfe2c, + XK_ISO_Fast_Cursor_Right = 0xfe2d, + XK_ISO_Fast_Cursor_Up = 0xfe2e, + XK_ISO_Fast_Cursor_Down = 0xfe2f, + XK_ISO_Continuous_Underline = 0xfe30, + XK_ISO_Discontinuous_Underline = 0xfe31, + XK_ISO_Emphasize = 0xfe32, + XK_ISO_Center_Object = 0xfe33, + XK_ISO_Enter = 0xfe34, + XK_dead_grave = 0xfe50, + XK_dead_acute = 0xfe51, + XK_dead_circumflex = 0xfe52, + XK_dead_tilde = 0xfe53, + XK_dead_macron = 0xfe54, + XK_dead_breve = 0xfe55, + XK_dead_abovedot = 0xfe56, + XK_dead_diaeresis = 0xfe57, + XK_dead_abovering = 0xfe58, + XK_dead_doubleacute = 0xfe59, + XK_dead_caron = 0xfe5a, + XK_dead_cedilla = 0xfe5b, + XK_dead_ogonek = 0xfe5c, + XK_dead_iota = 0xfe5d, + XK_dead_voiced_sound = 0xfe5e, + XK_dead_semivoiced_sound = 0xfe5f, + XK_dead_belowdot = 0xfe60, + XK_dead_hook = 0xfe61, + XK_dead_horn = 0xfe62, + XK_First_Virtual_Screen = 0xfed0, + XK_Prev_Virtual_Screen = 0xfed1, + XK_Next_Virtual_Screen = 0xfed2, + XK_Last_Virtual_Screen = 0xfed4, + XK_Terminate_Server = 0xfed5, + XK_AccessX_Enable = 0xfe70, + XK_AccessX_Feedback_Enable = 0xfe71, + XK_RepeatKeys_Enable = 0xfe72, + XK_SlowKeys_Enable = 0xfe73, + XK_BounceKeys_Enable = 0xfe74, + XK_StickyKeys_Enable = 0xfe75, + XK_MouseKeys_Enable = 0xfe76, + XK_MouseKeys_Accel_Enable = 0xfe77, + XK_Overlay1_Enable = 0xfe78, + XK_Overlay2_Enable = 0xfe79, + XK_AudibleBell_Enable = 0xfe7a, + XK_Pointer_Left = 0xfee0, + XK_Pointer_Right = 0xfee1, + XK_Pointer_Up = 0xfee2, + XK_Pointer_Down = 0xfee3, + XK_Pointer_UpLeft = 0xfee4, + XK_Pointer_UpRight = 0xfee5, + XK_Pointer_DownLeft = 0xfee6, + XK_Pointer_DownRight = 0xfee7, + XK_Pointer_Button_Dflt = 0xfee8, + XK_Pointer_Button1 = 0xfee9, + XK_Pointer_Button2 = 0xfeea, + XK_Pointer_Button3 = 0xfeeb, + XK_Pointer_Button4 = 0xfeec, + XK_Pointer_Button5 = 0xfeed, + XK_Pointer_DblClick_Dflt = 0xfeee, + XK_Pointer_DblClick1 = 0xfeef, + XK_Pointer_DblClick2 = 0xfef0, + XK_Pointer_DblClick3 = 0xfef1, + XK_Pointer_DblClick4 = 0xfef2, + XK_Pointer_DblClick5 = 0xfef3, + XK_Pointer_Drag_Dflt = 0xfef4, + XK_Pointer_Drag1 = 0xfef5, + XK_Pointer_Drag2 = 0xfef6, + XK_Pointer_Drag3 = 0xfef7, + XK_Pointer_Drag4 = 0xfef8, + XK_Pointer_Drag5 = 0xfefd, + XK_Pointer_EnableKeys = 0xfef9, + XK_Pointer_Accelerate = 0xfefa, + XK_Pointer_DfltBtnNext = 0xfefb, + XK_Pointer_DfltBtnPrev = 0xfefc, + XK_3270_Duplicate = 0xfd01, + XK_3270_FieldMark = 0xfd02, + XK_3270_Right2 = 0xfd03, + XK_3270_Left2 = 0xfd04, + XK_3270_BackTab = 0xfd05, + XK_3270_EraseEOF = 0xfd06, + XK_3270_EraseInput = 0xfd07, + XK_3270_Reset = 0xfd08, + XK_3270_Quit = 0xfd09, + XK_3270_PA1 = 0xfd0a, + XK_3270_PA2 = 0xfd0b, + XK_3270_PA3 = 0xfd0c, + XK_3270_Test = 0xfd0d, + XK_3270_Attn = 0xfd0e, + XK_3270_CursorBlink = 0xfd0f, + XK_3270_AltCursor = 0xfd10, + XK_3270_KeyClick = 0xfd11, + XK_3270_Jump = 0xfd12, + XK_3270_Ident = 0xfd13, + XK_3270_Rule = 0xfd14, + XK_3270_Copy = 0xfd15, + XK_3270_Play = 0xfd16, + XK_3270_Setup = 0xfd17, + XK_3270_Record = 0xfd18, + XK_3270_ChangeScreen = 0xfd19, + XK_3270_DeleteWord = 0xfd1a, + XK_3270_ExSelect = 0xfd1b, + XK_3270_CursorSelect = 0xfd1c, + XK_3270_PrintScreen = 0xfd1d, + XK_3270_Enter = 0xfd1e, + XK_space = 0x0020, /* U+0020 SPACE */ + XK_exclam = 0x0021, /* U+0021 EXCLAMATION MARK */ + XK_quotedbl = 0x0022, /* U+0022 QUOTATION MARK */ + XK_numbersign = 0x0023, /* U+0023 NUMBER SIGN */ + XK_dollar = 0x0024, /* U+0024 DOLLAR SIGN */ + XK_percent = 0x0025, /* U+0025 PERCENT SIGN */ + XK_ampersand = 0x0026, /* U+0026 AMPERSAND */ + XK_apostrophe = 0x0027, /* U+0027 APOSTROPHE */ + XK_quoteright = 0x0027, /* deprecated */ + XK_parenleft = 0x0028, /* U+0028 LEFT PARENTHESIS */ + XK_parenright = 0x0029, /* U+0029 RIGHT PARENTHESIS */ + XK_asterisk = 0x002a, /* U+002A ASTERISK */ + XK_plus = 0x002b, /* U+002B PLUS SIGN */ + XK_comma = 0x002c, /* U+002C COMMA */ + XK_minus = 0x002d, /* U+002D HYPHEN-MINUS */ + XK_period = 0x002e, /* U+002E FULL STOP */ + XK_slash = 0x002f, /* U+002F SOLIDUS */ + XK_0 = 0x0030, /* U+0030 DIGIT ZERO */ + XK_1 = 0x0031, /* U+0031 DIGIT ONE */ + XK_2 = 0x0032, /* U+0032 DIGIT TWO */ + XK_3 = 0x0033, /* U+0033 DIGIT THREE */ + XK_4 = 0x0034, /* U+0034 DIGIT FOUR */ + XK_5 = 0x0035, /* U+0035 DIGIT FIVE */ + XK_6 = 0x0036, /* U+0036 DIGIT SIX */ + XK_7 = 0x0037, /* U+0037 DIGIT SEVEN */ + XK_8 = 0x0038, /* U+0038 DIGIT EIGHT */ + XK_9 = 0x0039, /* U+0039 DIGIT NINE */ + XK_colon = 0x003a, /* U+003A COLON */ + XK_semicolon = 0x003b, /* U+003B SEMICOLON */ + XK_less = 0x003c, /* U+003C LESS-THAN SIGN */ + XK_equal = 0x003d, /* U+003D EQUALS SIGN */ + XK_greater = 0x003e, /* U+003E GREATER-THAN SIGN */ + XK_question = 0x003f, /* U+003F QUESTION MARK */ + XK_at = 0x0040, /* U+0040 COMMERCIAL AT */ + XK_A = 0x0041, /* U+0041 LATIN CAPITAL LETTER A */ + XK_B = 0x0042, /* U+0042 LATIN CAPITAL LETTER B */ + XK_C = 0x0043, /* U+0043 LATIN CAPITAL LETTER C */ + XK_D = 0x0044, /* U+0044 LATIN CAPITAL LETTER D */ + XK_E = 0x0045, /* U+0045 LATIN CAPITAL LETTER E */ + XK_F = 0x0046, /* U+0046 LATIN CAPITAL LETTER F */ + XK_G = 0x0047, /* U+0047 LATIN CAPITAL LETTER G */ + XK_H = 0x0048, /* U+0048 LATIN CAPITAL LETTER H */ + XK_I = 0x0049, /* U+0049 LATIN CAPITAL LETTER I */ + XK_J = 0x004a, /* U+004A LATIN CAPITAL LETTER J */ + XK_K = 0x004b, /* U+004B LATIN CAPITAL LETTER K */ + XK_L = 0x004c, /* U+004C LATIN CAPITAL LETTER L */ + XK_M = 0x004d, /* U+004D LATIN CAPITAL LETTER M */ + XK_N = 0x004e, /* U+004E LATIN CAPITAL LETTER N */ + XK_O = 0x004f, /* U+004F LATIN CAPITAL LETTER O */ + XK_P = 0x0050, /* U+0050 LATIN CAPITAL LETTER P */ + XK_Q = 0x0051, /* U+0051 LATIN CAPITAL LETTER Q */ + XK_R = 0x0052, /* U+0052 LATIN CAPITAL LETTER R */ + XK_S = 0x0053, /* U+0053 LATIN CAPITAL LETTER S */ + XK_T = 0x0054, /* U+0054 LATIN CAPITAL LETTER T */ + XK_U = 0x0055, /* U+0055 LATIN CAPITAL LETTER U */ + XK_V = 0x0056, /* U+0056 LATIN CAPITAL LETTER V */ + XK_W = 0x0057, /* U+0057 LATIN CAPITAL LETTER W */ + XK_X = 0x0058, /* U+0058 LATIN CAPITAL LETTER X */ + XK_Y = 0x0059, /* U+0059 LATIN CAPITAL LETTER Y */ + XK_Z = 0x005a, /* U+005A LATIN CAPITAL LETTER Z */ + XK_bracketleft = 0x005b, /* U+005B LEFT SQUARE BRACKET */ + XK_backslash = 0x005c, /* U+005C REVERSE SOLIDUS */ + XK_bracketright = 0x005d, /* U+005D RIGHT SQUARE BRACKET */ + XK_asciicircum = 0x005e, /* U+005E CIRCUMFLEX ACCENT */ + XK_underscore = 0x005f, /* U+005F LOW LINE */ + XK_grave = 0x0060, /* U+0060 GRAVE ACCENT */ + XK_quoteleft = 0x0060, /* deprecated */ + XK_a = 0x0061, /* U+0061 LATIN SMALL LETTER A */ + XK_b = 0x0062, /* U+0062 LATIN SMALL LETTER B */ + XK_c = 0x0063, /* U+0063 LATIN SMALL LETTER C */ + XK_d = 0x0064, /* U+0064 LATIN SMALL LETTER D */ + XK_e = 0x0065, /* U+0065 LATIN SMALL LETTER E */ + XK_f = 0x0066, /* U+0066 LATIN SMALL LETTER F */ + XK_g = 0x0067, /* U+0067 LATIN SMALL LETTER G */ + XK_h = 0x0068, /* U+0068 LATIN SMALL LETTER H */ + XK_i = 0x0069, /* U+0069 LATIN SMALL LETTER I */ + XK_j = 0x006a, /* U+006A LATIN SMALL LETTER J */ + XK_k = 0x006b, /* U+006B LATIN SMALL LETTER K */ + XK_l = 0x006c, /* U+006C LATIN SMALL LETTER L */ + XK_m = 0x006d, /* U+006D LATIN SMALL LETTER M */ + XK_n = 0x006e, /* U+006E LATIN SMALL LETTER N */ + XK_o = 0x006f, /* U+006F LATIN SMALL LETTER O */ + XK_p = 0x0070, /* U+0070 LATIN SMALL LETTER P */ + XK_q = 0x0071, /* U+0071 LATIN SMALL LETTER Q */ + XK_r = 0x0072, /* U+0072 LATIN SMALL LETTER R */ + XK_s = 0x0073, /* U+0073 LATIN SMALL LETTER S */ + XK_t = 0x0074, /* U+0074 LATIN SMALL LETTER T */ + XK_u = 0x0075, /* U+0075 LATIN SMALL LETTER U */ + XK_v = 0x0076, /* U+0076 LATIN SMALL LETTER V */ + XK_w = 0x0077, /* U+0077 LATIN SMALL LETTER W */ + XK_x = 0x0078, /* U+0078 LATIN SMALL LETTER X */ + XK_y = 0x0079, /* U+0079 LATIN SMALL LETTER Y */ + XK_z = 0x007a, /* U+007A LATIN SMALL LETTER Z */ + XK_braceleft = 0x007b, /* U+007B LEFT CURLY BRACKET */ + XK_bar = 0x007c, /* U+007C VERTICAL LINE */ + XK_braceright = 0x007d, /* U+007D RIGHT CURLY BRACKET */ + XK_asciitilde = 0x007e, /* U+007E TILDE */ + XK_nobreakspace = 0x00a0, /* U+00A0 NO-BREAK SPACE */ + XK_exclamdown = 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */ + XK_cent = 0x00a2, /* U+00A2 CENT SIGN */ + XK_sterling = 0x00a3, /* U+00A3 POUND SIGN */ + XK_currency = 0x00a4, /* U+00A4 CURRENCY SIGN */ + XK_yen = 0x00a5, /* U+00A5 YEN SIGN */ + XK_brokenbar = 0x00a6, /* U+00A6 BROKEN BAR */ + XK_section = 0x00a7, /* U+00A7 SECTION SIGN */ + XK_diaeresis = 0x00a8, /* U+00A8 DIAERESIS */ + XK_copyright = 0x00a9, /* U+00A9 COPYRIGHT SIGN */ + XK_ordfeminine = 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */ + XK_guillemotleft = 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ + XK_notsign = 0x00ac, /* U+00AC NOT SIGN */ + XK_hyphen = 0x00ad, /* U+00AD SOFT HYPHEN */ + XK_registered = 0x00ae, /* U+00AE REGISTERED SIGN */ + XK_macron = 0x00af, /* U+00AF MACRON */ + XK_degree = 0x00b0, /* U+00B0 DEGREE SIGN */ + XK_plusminus = 0x00b1, /* U+00B1 PLUS-MINUS SIGN */ + XK_twosuperior = 0x00b2, /* U+00B2 SUPERSCRIPT TWO */ + XK_threesuperior = 0x00b3, /* U+00B3 SUPERSCRIPT THREE */ + XK_acute = 0x00b4, /* U+00B4 ACUTE ACCENT */ + XK_mu = 0x00b5, /* U+00B5 MICRO SIGN */ + XK_paragraph = 0x00b6, /* U+00B6 PILCROW SIGN */ + XK_periodcentered = 0x00b7, /* U+00B7 MIDDLE DOT */ + XK_cedilla = 0x00b8, /* U+00B8 CEDILLA */ + XK_onesuperior = 0x00b9, /* U+00B9 SUPERSCRIPT ONE */ + XK_masculine = 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */ + XK_guillemotright = 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ + XK_onequarter = 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */ + XK_onehalf = 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */ + XK_threequarters = 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */ + XK_questiondown = 0x00bf, /* U+00BF INVERTED QUESTION MARK */ + XK_Agrave = 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */ + XK_Aacute = 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */ + XK_Acircumflex = 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ + XK_Atilde = 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */ + XK_Adiaeresis = 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */ + XK_Aring = 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */ + XK_AE = 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */ + XK_Ccedilla = 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */ + XK_Egrave = 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */ + XK_Eacute = 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */ + XK_Ecircumflex = 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ + XK_Ediaeresis = 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */ + XK_Igrave = 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */ + XK_Iacute = 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */ + XK_Icircumflex = 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ + XK_Idiaeresis = 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */ + XK_ETH = 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */ + XK_Eth = 0x00d0, /* deprecated */ + XK_Ntilde = 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */ + XK_Ograve = 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */ + XK_Oacute = 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */ + XK_Ocircumflex = 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ + XK_Otilde = 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */ + XK_Odiaeresis = 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */ + XK_multiply = 0x00d7, /* U+00D7 MULTIPLICATION SIGN */ + XK_Oslash = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ + XK_Ooblique = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ + XK_Ugrave = 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */ + XK_Uacute = 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */ + XK_Ucircumflex = 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ + XK_Udiaeresis = 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */ + XK_Yacute = 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */ + XK_THORN = 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */ + XK_Thorn = 0x00de, /* deprecated */ + XK_ssharp = 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */ + XK_agrave = 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */ + XK_aacute = 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */ + XK_acircumflex = 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */ + XK_atilde = 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */ + XK_adiaeresis = 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */ + XK_aring = 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */ + XK_ae = 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */ + XK_ccedilla = 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */ + XK_egrave = 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */ + XK_eacute = 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */ + XK_ecircumflex = 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */ + XK_ediaeresis = 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */ + XK_igrave = 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */ + XK_iacute = 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */ + XK_icircumflex = 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */ + XK_idiaeresis = 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */ + XK_eth = 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */ + XK_ntilde = 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */ + XK_ograve = 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */ + XK_oacute = 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */ + XK_ocircumflex = 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */ + XK_otilde = 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */ + XK_odiaeresis = 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */ + XK_division = 0x00f7, /* U+00F7 DIVISION SIGN */ + XK_oslash = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ + XK_ooblique = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ + XK_ugrave = 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */ + XK_uacute = 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */ + XK_ucircumflex = 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */ + XK_udiaeresis = 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */ + XK_yacute = 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */ + XK_thorn = 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */ + XK_ydiaeresis = 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */ + XK_Aogonek = 0x01a1, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK */ + XK_breve = 0x01a2, /* U+02D8 BREVE */ + XK_Lstroke = 0x01a3, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE */ + XK_Lcaron = 0x01a5, /* U+013D LATIN CAPITAL LETTER L WITH CARON */ + XK_Sacute = 0x01a6, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE */ + XK_Scaron = 0x01a9, /* U+0160 LATIN CAPITAL LETTER S WITH CARON */ + XK_Scedilla = 0x01aa, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA */ + XK_Tcaron = 0x01ab, /* U+0164 LATIN CAPITAL LETTER T WITH CARON */ + XK_Zacute = 0x01ac, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE */ + XK_Zcaron = 0x01ae, /* U+017D LATIN CAPITAL LETTER Z WITH CARON */ + XK_Zabovedot = 0x01af, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + XK_aogonek = 0x01b1, /* U+0105 LATIN SMALL LETTER A WITH OGONEK */ + XK_ogonek = 0x01b2, /* U+02DB OGONEK */ + XK_lstroke = 0x01b3, /* U+0142 LATIN SMALL LETTER L WITH STROKE */ + XK_lcaron = 0x01b5, /* U+013E LATIN SMALL LETTER L WITH CARON */ + XK_sacute = 0x01b6, /* U+015B LATIN SMALL LETTER S WITH ACUTE */ + XK_caron = 0x01b7, /* U+02C7 CARON */ + XK_scaron = 0x01b9, /* U+0161 LATIN SMALL LETTER S WITH CARON */ + XK_scedilla = 0x01ba, /* U+015F LATIN SMALL LETTER S WITH CEDILLA */ + XK_tcaron = 0x01bb, /* U+0165 LATIN SMALL LETTER T WITH CARON */ + XK_zacute = 0x01bc, /* U+017A LATIN SMALL LETTER Z WITH ACUTE */ + XK_doubleacute = 0x01bd, /* U+02DD DOUBLE ACUTE ACCENT */ + XK_zcaron = 0x01be, /* U+017E LATIN SMALL LETTER Z WITH CARON */ + XK_zabovedot = 0x01bf, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE */ + XK_Racute = 0x01c0, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE */ + XK_Abreve = 0x01c3, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE */ + XK_Lacute = 0x01c5, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE */ + XK_Cacute = 0x01c6, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE */ + XK_Ccaron = 0x01c8, /* U+010C LATIN CAPITAL LETTER C WITH CARON */ + XK_Eogonek = 0x01ca, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK */ + XK_Ecaron = 0x01cc, /* U+011A LATIN CAPITAL LETTER E WITH CARON */ + XK_Dcaron = 0x01cf, /* U+010E LATIN CAPITAL LETTER D WITH CARON */ + XK_Dstroke = 0x01d0, /* U+0110 LATIN CAPITAL LETTER D WITH STROKE */ + XK_Nacute = 0x01d1, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE */ + XK_Ncaron = 0x01d2, /* U+0147 LATIN CAPITAL LETTER N WITH CARON */ + XK_Odoubleacute = 0x01d5, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + XK_Rcaron = 0x01d8, /* U+0158 LATIN CAPITAL LETTER R WITH CARON */ + XK_Uring = 0x01d9, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE */ + XK_Udoubleacute = 0x01db, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + XK_Tcedilla = 0x01de, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA */ + XK_racute = 0x01e0, /* U+0155 LATIN SMALL LETTER R WITH ACUTE */ + XK_abreve = 0x01e3, /* U+0103 LATIN SMALL LETTER A WITH BREVE */ + XK_lacute = 0x01e5, /* U+013A LATIN SMALL LETTER L WITH ACUTE */ + XK_cacute = 0x01e6, /* U+0107 LATIN SMALL LETTER C WITH ACUTE */ + XK_ccaron = 0x01e8, /* U+010D LATIN SMALL LETTER C WITH CARON */ + XK_eogonek = 0x01ea, /* U+0119 LATIN SMALL LETTER E WITH OGONEK */ + XK_ecaron = 0x01ec, /* U+011B LATIN SMALL LETTER E WITH CARON */ + XK_dcaron = 0x01ef, /* U+010F LATIN SMALL LETTER D WITH CARON */ + XK_dstroke = 0x01f0, /* U+0111 LATIN SMALL LETTER D WITH STROKE */ + XK_nacute = 0x01f1, /* U+0144 LATIN SMALL LETTER N WITH ACUTE */ + XK_ncaron = 0x01f2, /* U+0148 LATIN SMALL LETTER N WITH CARON */ + XK_odoubleacute = 0x01f5, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + XK_udoubleacute = 0x01fb, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + XK_rcaron = 0x01f8, /* U+0159 LATIN SMALL LETTER R WITH CARON */ + XK_uring = 0x01f9, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE */ + XK_tcedilla = 0x01fe, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA */ + XK_abovedot = 0x01ff, /* U+02D9 DOT ABOVE */ + XK_Hstroke = 0x02a1, /* U+0126 LATIN CAPITAL LETTER H WITH STROKE */ + XK_Hcircumflex = 0x02a6, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + XK_Iabovedot = 0x02a9, /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */ + XK_Gbreve = 0x02ab, /* U+011E LATIN CAPITAL LETTER G WITH BREVE */ + XK_Jcircumflex = 0x02ac, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + XK_hstroke = 0x02b1, /* U+0127 LATIN SMALL LETTER H WITH STROKE */ + XK_hcircumflex = 0x02b6, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX */ + XK_idotless = 0x02b9, /* U+0131 LATIN SMALL LETTER DOTLESS I */ + XK_gbreve = 0x02bb, /* U+011F LATIN SMALL LETTER G WITH BREVE */ + XK_jcircumflex = 0x02bc, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX */ + XK_Cabovedot = 0x02c5, /* U+010A LATIN CAPITAL LETTER C WITH DOT ABOVE */ + XK_Ccircumflex = 0x02c6, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + XK_Gabovedot = 0x02d5, /* U+0120 LATIN CAPITAL LETTER G WITH DOT ABOVE */ + XK_Gcircumflex = 0x02d8, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + XK_Ubreve = 0x02dd, /* U+016C LATIN CAPITAL LETTER U WITH BREVE */ + XK_Scircumflex = 0x02de, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + XK_cabovedot = 0x02e5, /* U+010B LATIN SMALL LETTER C WITH DOT ABOVE */ + XK_ccircumflex = 0x02e6, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX */ + XK_gabovedot = 0x02f5, /* U+0121 LATIN SMALL LETTER G WITH DOT ABOVE */ + XK_gcircumflex = 0x02f8, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX */ + XK_ubreve = 0x02fd, /* U+016D LATIN SMALL LETTER U WITH BREVE */ + XK_scircumflex = 0x02fe, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX */ + XK_kra = 0x03a2, /* U+0138 LATIN SMALL LETTER KRA */ + XK_kappa = 0x03a2, /* deprecated */ + XK_Rcedilla = 0x03a3, /* U+0156 LATIN CAPITAL LETTER R WITH CEDILLA */ + XK_Itilde = 0x03a5, /* U+0128 LATIN CAPITAL LETTER I WITH TILDE */ + XK_Lcedilla = 0x03a6, /* U+013B LATIN CAPITAL LETTER L WITH CEDILLA */ + XK_Emacron = 0x03aa, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON */ + XK_Gcedilla = 0x03ab, /* U+0122 LATIN CAPITAL LETTER G WITH CEDILLA */ + XK_Tslash = 0x03ac, /* U+0166 LATIN CAPITAL LETTER T WITH STROKE */ + XK_rcedilla = 0x03b3, /* U+0157 LATIN SMALL LETTER R WITH CEDILLA */ + XK_itilde = 0x03b5, /* U+0129 LATIN SMALL LETTER I WITH TILDE */ + XK_lcedilla = 0x03b6, /* U+013C LATIN SMALL LETTER L WITH CEDILLA */ + XK_emacron = 0x03ba, /* U+0113 LATIN SMALL LETTER E WITH MACRON */ + XK_gcedilla = 0x03bb, /* U+0123 LATIN SMALL LETTER G WITH CEDILLA */ + XK_tslash = 0x03bc, /* U+0167 LATIN SMALL LETTER T WITH STROKE */ + XK_ENG = 0x03bd, /* U+014A LATIN CAPITAL LETTER ENG */ + XK_eng = 0x03bf, /* U+014B LATIN SMALL LETTER ENG */ + XK_Amacron = 0x03c0, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON */ + XK_Iogonek = 0x03c7, /* U+012E LATIN CAPITAL LETTER I WITH OGONEK */ + XK_Eabovedot = 0x03cc, /* U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE */ + XK_Imacron = 0x03cf, /* U+012A LATIN CAPITAL LETTER I WITH MACRON */ + XK_Ncedilla = 0x03d1, /* U+0145 LATIN CAPITAL LETTER N WITH CEDILLA */ + XK_Omacron = 0x03d2, /* U+014C LATIN CAPITAL LETTER O WITH MACRON */ + XK_Kcedilla = 0x03d3, /* U+0136 LATIN CAPITAL LETTER K WITH CEDILLA */ + XK_Uogonek = 0x03d9, /* U+0172 LATIN CAPITAL LETTER U WITH OGONEK */ + XK_Utilde = 0x03dd, /* U+0168 LATIN CAPITAL LETTER U WITH TILDE */ + XK_Umacron = 0x03de, /* U+016A LATIN CAPITAL LETTER U WITH MACRON */ + XK_amacron = 0x03e0, /* U+0101 LATIN SMALL LETTER A WITH MACRON */ + XK_iogonek = 0x03e7, /* U+012F LATIN SMALL LETTER I WITH OGONEK */ + XK_eabovedot = 0x03ec, /* U+0117 LATIN SMALL LETTER E WITH DOT ABOVE */ + XK_imacron = 0x03ef, /* U+012B LATIN SMALL LETTER I WITH MACRON */ + XK_ncedilla = 0x03f1, /* U+0146 LATIN SMALL LETTER N WITH CEDILLA */ + XK_omacron = 0x03f2, /* U+014D LATIN SMALL LETTER O WITH MACRON */ + XK_kcedilla = 0x03f3, /* U+0137 LATIN SMALL LETTER K WITH CEDILLA */ + XK_uogonek = 0x03f9, /* U+0173 LATIN SMALL LETTER U WITH OGONEK */ + XK_utilde = 0x03fd, /* U+0169 LATIN SMALL LETTER U WITH TILDE */ + XK_umacron = 0x03fe, /* U+016B LATIN SMALL LETTER U WITH MACRON */ + XK_Babovedot = 0x1001e02, /* U+1E02 LATIN CAPITAL LETTER B WITH DOT ABOVE */ + XK_babovedot = 0x1001e03, /* U+1E03 LATIN SMALL LETTER B WITH DOT ABOVE */ + XK_Dabovedot = 0x1001e0a, /* U+1E0A LATIN CAPITAL LETTER D WITH DOT ABOVE */ + XK_Wgrave = 0x1001e80, /* U+1E80 LATIN CAPITAL LETTER W WITH GRAVE */ + XK_Wacute = 0x1001e82, /* U+1E82 LATIN CAPITAL LETTER W WITH ACUTE */ + XK_dabovedot = 0x1001e0b, /* U+1E0B LATIN SMALL LETTER D WITH DOT ABOVE */ + XK_Ygrave = 0x1001ef2, /* U+1EF2 LATIN CAPITAL LETTER Y WITH GRAVE */ + XK_Fabovedot = 0x1001e1e, /* U+1E1E LATIN CAPITAL LETTER F WITH DOT ABOVE */ + XK_fabovedot = 0x1001e1f, /* U+1E1F LATIN SMALL LETTER F WITH DOT ABOVE */ + XK_Mabovedot = 0x1001e40, /* U+1E40 LATIN CAPITAL LETTER M WITH DOT ABOVE */ + XK_mabovedot = 0x1001e41, /* U+1E41 LATIN SMALL LETTER M WITH DOT ABOVE */ + XK_Pabovedot = 0x1001e56, /* U+1E56 LATIN CAPITAL LETTER P WITH DOT ABOVE */ + XK_wgrave = 0x1001e81, /* U+1E81 LATIN SMALL LETTER W WITH GRAVE */ + XK_pabovedot = 0x1001e57, /* U+1E57 LATIN SMALL LETTER P WITH DOT ABOVE */ + XK_wacute = 0x1001e83, /* U+1E83 LATIN SMALL LETTER W WITH ACUTE */ + XK_Sabovedot = 0x1001e60, /* U+1E60 LATIN CAPITAL LETTER S WITH DOT ABOVE */ + XK_ygrave = 0x1001ef3, /* U+1EF3 LATIN SMALL LETTER Y WITH GRAVE */ + XK_Wdiaeresis = 0x1001e84, /* U+1E84 LATIN CAPITAL LETTER W WITH DIAERESIS */ + XK_wdiaeresis = 0x1001e85, /* U+1E85 LATIN SMALL LETTER W WITH DIAERESIS */ + XK_sabovedot = 0x1001e61, /* U+1E61 LATIN SMALL LETTER S WITH DOT ABOVE */ + XK_Wcircumflex = 0x1000174, /* U+0174 LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ + XK_Tabovedot = 0x1001e6a, /* U+1E6A LATIN CAPITAL LETTER T WITH DOT ABOVE */ + XK_Ycircumflex = 0x1000176, /* U+0176 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ + XK_wcircumflex = 0x1000175, /* U+0175 LATIN SMALL LETTER W WITH CIRCUMFLEX */ + XK_tabovedot = 0x1001e6b, /* U+1E6B LATIN SMALL LETTER T WITH DOT ABOVE */ + XK_ycircumflex = 0x1000177, /* U+0177 LATIN SMALL LETTER Y WITH CIRCUMFLEX */ + XK_OE = 0x13bc, /* U+0152 LATIN CAPITAL LIGATURE OE */ + XK_oe = 0x13bd, /* U+0153 LATIN SMALL LIGATURE OE */ + XK_Ydiaeresis = 0x13be, /* U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS */ + XK_overline = 0x047e, /* U+203E OVERLINE */ + XK_kana_fullstop = 0x04a1, /* U+3002 IDEOGRAPHIC FULL STOP */ + XK_kana_openingbracket = 0x04a2, /* U+300C LEFT CORNER BRACKET */ + XK_kana_closingbracket = 0x04a3, /* U+300D RIGHT CORNER BRACKET */ + XK_kana_comma = 0x04a4, /* U+3001 IDEOGRAPHIC COMMA */ + XK_kana_conjunctive = 0x04a5, /* U+30FB KATAKANA MIDDLE DOT */ + XK_kana_middledot = 0x04a5, /* deprecated */ + XK_kana_WO = 0x04a6, /* U+30F2 KATAKANA LETTER WO */ + XK_kana_a = 0x04a7, /* U+30A1 KATAKANA LETTER SMALL A */ + XK_kana_i = 0x04a8, /* U+30A3 KATAKANA LETTER SMALL I */ + XK_kana_u = 0x04a9, /* U+30A5 KATAKANA LETTER SMALL U */ + XK_kana_e = 0x04aa, /* U+30A7 KATAKANA LETTER SMALL E */ + XK_kana_o = 0x04ab, /* U+30A9 KATAKANA LETTER SMALL O */ + XK_kana_ya = 0x04ac, /* U+30E3 KATAKANA LETTER SMALL YA */ + XK_kana_yu = 0x04ad, /* U+30E5 KATAKANA LETTER SMALL YU */ + XK_kana_yo = 0x04ae, /* U+30E7 KATAKANA LETTER SMALL YO */ + XK_kana_tsu = 0x04af, /* U+30C3 KATAKANA LETTER SMALL TU */ + XK_kana_tu = 0x04af, /* deprecated */ + XK_prolongedsound = 0x04b0, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + XK_kana_A = 0x04b1, /* U+30A2 KATAKANA LETTER A */ + XK_kana_I = 0x04b2, /* U+30A4 KATAKANA LETTER I */ + XK_kana_U = 0x04b3, /* U+30A6 KATAKANA LETTER U */ + XK_kana_E = 0x04b4, /* U+30A8 KATAKANA LETTER E */ + XK_kana_O = 0x04b5, /* U+30AA KATAKANA LETTER O */ + XK_kana_KA = 0x04b6, /* U+30AB KATAKANA LETTER KA */ + XK_kana_KI = 0x04b7, /* U+30AD KATAKANA LETTER KI */ + XK_kana_KU = 0x04b8, /* U+30AF KATAKANA LETTER KU */ + XK_kana_KE = 0x04b9, /* U+30B1 KATAKANA LETTER KE */ + XK_kana_KO = 0x04ba, /* U+30B3 KATAKANA LETTER KO */ + XK_kana_SA = 0x04bb, /* U+30B5 KATAKANA LETTER SA */ + XK_kana_SHI = 0x04bc, /* U+30B7 KATAKANA LETTER SI */ + XK_kana_SU = 0x04bd, /* U+30B9 KATAKANA LETTER SU */ + XK_kana_SE = 0x04be, /* U+30BB KATAKANA LETTER SE */ + XK_kana_SO = 0x04bf, /* U+30BD KATAKANA LETTER SO */ + XK_kana_TA = 0x04c0, /* U+30BF KATAKANA LETTER TA */ + XK_kana_CHI = 0x04c1, /* U+30C1 KATAKANA LETTER TI */ + XK_kana_TI = 0x04c1, /* deprecated */ + XK_kana_TSU = 0x04c2, /* U+30C4 KATAKANA LETTER TU */ + XK_kana_TU = 0x04c2, /* deprecated */ + XK_kana_TE = 0x04c3, /* U+30C6 KATAKANA LETTER TE */ + XK_kana_TO = 0x04c4, /* U+30C8 KATAKANA LETTER TO */ + XK_kana_NA = 0x04c5, /* U+30CA KATAKANA LETTER NA */ + XK_kana_NI = 0x04c6, /* U+30CB KATAKANA LETTER NI */ + XK_kana_NU = 0x04c7, /* U+30CC KATAKANA LETTER NU */ + XK_kana_NE = 0x04c8, /* U+30CD KATAKANA LETTER NE */ + XK_kana_NO = 0x04c9, /* U+30CE KATAKANA LETTER NO */ + XK_kana_HA = 0x04ca, /* U+30CF KATAKANA LETTER HA */ + XK_kana_HI = 0x04cb, /* U+30D2 KATAKANA LETTER HI */ + XK_kana_FU = 0x04cc, /* U+30D5 KATAKANA LETTER HU */ + XK_kana_HU = 0x04cc, /* deprecated */ + XK_kana_HE = 0x04cd, /* U+30D8 KATAKANA LETTER HE */ + XK_kana_HO = 0x04ce, /* U+30DB KATAKANA LETTER HO */ + XK_kana_MA = 0x04cf, /* U+30DE KATAKANA LETTER MA */ + XK_kana_MI = 0x04d0, /* U+30DF KATAKANA LETTER MI */ + XK_kana_MU = 0x04d1, /* U+30E0 KATAKANA LETTER MU */ + XK_kana_ME = 0x04d2, /* U+30E1 KATAKANA LETTER ME */ + XK_kana_MO = 0x04d3, /* U+30E2 KATAKANA LETTER MO */ + XK_kana_YA = 0x04d4, /* U+30E4 KATAKANA LETTER YA */ + XK_kana_YU = 0x04d5, /* U+30E6 KATAKANA LETTER YU */ + XK_kana_YO = 0x04d6, /* U+30E8 KATAKANA LETTER YO */ + XK_kana_RA = 0x04d7, /* U+30E9 KATAKANA LETTER RA */ + XK_kana_RI = 0x04d8, /* U+30EA KATAKANA LETTER RI */ + XK_kana_RU = 0x04d9, /* U+30EB KATAKANA LETTER RU */ + XK_kana_RE = 0x04da, /* U+30EC KATAKANA LETTER RE */ + XK_kana_RO = 0x04db, /* U+30ED KATAKANA LETTER RO */ + XK_kana_WA = 0x04dc, /* U+30EF KATAKANA LETTER WA */ + XK_kana_N = 0x04dd, /* U+30F3 KATAKANA LETTER N */ + XK_voicedsound = 0x04de, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ + XK_semivoicedsound = 0x04df, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + XK_kana_switch = 0xff7e, /* Alias for mode_switch */ + XK_Farsi_0 = 0x10006f0, /* U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO */ + XK_Farsi_1 = 0x10006f1, /* U+06F1 EXTENDED ARABIC-INDIC DIGIT ONE */ + XK_Farsi_2 = 0x10006f2, /* U+06F2 EXTENDED ARABIC-INDIC DIGIT TWO */ + XK_Farsi_3 = 0x10006f3, /* U+06F3 EXTENDED ARABIC-INDIC DIGIT THREE */ + XK_Farsi_4 = 0x10006f4, /* U+06F4 EXTENDED ARABIC-INDIC DIGIT FOUR */ + XK_Farsi_5 = 0x10006f5, /* U+06F5 EXTENDED ARABIC-INDIC DIGIT FIVE */ + XK_Farsi_6 = 0x10006f6, /* U+06F6 EXTENDED ARABIC-INDIC DIGIT SIX */ + XK_Farsi_7 = 0x10006f7, /* U+06F7 EXTENDED ARABIC-INDIC DIGIT SEVEN */ + XK_Farsi_8 = 0x10006f8, /* U+06F8 EXTENDED ARABIC-INDIC DIGIT EIGHT */ + XK_Farsi_9 = 0x10006f9, /* U+06F9 EXTENDED ARABIC-INDIC DIGIT NINE */ + XK_Arabic_percent = 0x100066a, /* U+066A ARABIC PERCENT SIGN */ + XK_Arabic_superscript_alef = 0x1000670, /* U+0670 ARABIC LETTER SUPERSCRIPT ALEF */ + XK_Arabic_tteh = 0x1000679, /* U+0679 ARABIC LETTER TTEH */ + XK_Arabic_peh = 0x100067e, /* U+067E ARABIC LETTER PEH */ + XK_Arabic_tcheh = 0x1000686, /* U+0686 ARABIC LETTER TCHEH */ + XK_Arabic_ddal = 0x1000688, /* U+0688 ARABIC LETTER DDAL */ + XK_Arabic_rreh = 0x1000691, /* U+0691 ARABIC LETTER RREH */ + XK_Arabic_comma = 0x05ac, /* U+060C ARABIC COMMA */ + XK_Arabic_fullstop = 0x10006d4, /* U+06D4 ARABIC FULL STOP */ + XK_Arabic_0 = 0x1000660, /* U+0660 ARABIC-INDIC DIGIT ZERO */ + XK_Arabic_1 = 0x1000661, /* U+0661 ARABIC-INDIC DIGIT ONE */ + XK_Arabic_2 = 0x1000662, /* U+0662 ARABIC-INDIC DIGIT TWO */ + XK_Arabic_3 = 0x1000663, /* U+0663 ARABIC-INDIC DIGIT THREE */ + XK_Arabic_4 = 0x1000664, /* U+0664 ARABIC-INDIC DIGIT FOUR */ + XK_Arabic_5 = 0x1000665, /* U+0665 ARABIC-INDIC DIGIT FIVE */ + XK_Arabic_6 = 0x1000666, /* U+0666 ARABIC-INDIC DIGIT SIX */ + XK_Arabic_7 = 0x1000667, /* U+0667 ARABIC-INDIC DIGIT SEVEN */ + XK_Arabic_8 = 0x1000668, /* U+0668 ARABIC-INDIC DIGIT EIGHT */ + XK_Arabic_9 = 0x1000669, /* U+0669 ARABIC-INDIC DIGIT NINE */ + XK_Arabic_semicolon = 0x05bb, /* U+061B ARABIC SEMICOLON */ + XK_Arabic_question_mark = 0x05bf, /* U+061F ARABIC QUESTION MARK */ + XK_Arabic_hamza = 0x05c1, /* U+0621 ARABIC LETTER HAMZA */ + XK_Arabic_maddaonalef = 0x05c2, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */ + XK_Arabic_hamzaonalef = 0x05c3, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */ + XK_Arabic_hamzaonwaw = 0x05c4, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */ + XK_Arabic_hamzaunderalef = 0x05c5, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */ + XK_Arabic_hamzaonyeh = 0x05c6, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */ + XK_Arabic_alef = 0x05c7, /* U+0627 ARABIC LETTER ALEF */ + XK_Arabic_beh = 0x05c8, /* U+0628 ARABIC LETTER BEH */ + XK_Arabic_tehmarbuta = 0x05c9, /* U+0629 ARABIC LETTER TEH MARBUTA */ + XK_Arabic_teh = 0x05ca, /* U+062A ARABIC LETTER TEH */ + XK_Arabic_theh = 0x05cb, /* U+062B ARABIC LETTER THEH */ + XK_Arabic_jeem = 0x05cc, /* U+062C ARABIC LETTER JEEM */ + XK_Arabic_hah = 0x05cd, /* U+062D ARABIC LETTER HAH */ + XK_Arabic_khah = 0x05ce, /* U+062E ARABIC LETTER KHAH */ + XK_Arabic_dal = 0x05cf, /* U+062F ARABIC LETTER DAL */ + XK_Arabic_thal = 0x05d0, /* U+0630 ARABIC LETTER THAL */ + XK_Arabic_ra = 0x05d1, /* U+0631 ARABIC LETTER REH */ + XK_Arabic_zain = 0x05d2, /* U+0632 ARABIC LETTER ZAIN */ + XK_Arabic_seen = 0x05d3, /* U+0633 ARABIC LETTER SEEN */ + XK_Arabic_sheen = 0x05d4, /* U+0634 ARABIC LETTER SHEEN */ + XK_Arabic_sad = 0x05d5, /* U+0635 ARABIC LETTER SAD */ + XK_Arabic_dad = 0x05d6, /* U+0636 ARABIC LETTER DAD */ + XK_Arabic_tah = 0x05d7, /* U+0637 ARABIC LETTER TAH */ + XK_Arabic_zah = 0x05d8, /* U+0638 ARABIC LETTER ZAH */ + XK_Arabic_ain = 0x05d9, /* U+0639 ARABIC LETTER AIN */ + XK_Arabic_ghain = 0x05da, /* U+063A ARABIC LETTER GHAIN */ + XK_Arabic_tatweel = 0x05e0, /* U+0640 ARABIC TATWEEL */ + XK_Arabic_feh = 0x05e1, /* U+0641 ARABIC LETTER FEH */ + XK_Arabic_qaf = 0x05e2, /* U+0642 ARABIC LETTER QAF */ + XK_Arabic_kaf = 0x05e3, /* U+0643 ARABIC LETTER KAF */ + XK_Arabic_lam = 0x05e4, /* U+0644 ARABIC LETTER LAM */ + XK_Arabic_meem = 0x05e5, /* U+0645 ARABIC LETTER MEEM */ + XK_Arabic_noon = 0x05e6, /* U+0646 ARABIC LETTER NOON */ + XK_Arabic_ha = 0x05e7, /* U+0647 ARABIC LETTER HEH */ + XK_Arabic_heh = 0x05e7, /* deprecated */ + XK_Arabic_waw = 0x05e8, /* U+0648 ARABIC LETTER WAW */ + XK_Arabic_alefmaksura = 0x05e9, /* U+0649 ARABIC LETTER ALEF MAKSURA */ + XK_Arabic_yeh = 0x05ea, /* U+064A ARABIC LETTER YEH */ + XK_Arabic_fathatan = 0x05eb, /* U+064B ARABIC FATHATAN */ + XK_Arabic_dammatan = 0x05ec, /* U+064C ARABIC DAMMATAN */ + XK_Arabic_kasratan = 0x05ed, /* U+064D ARABIC KASRATAN */ + XK_Arabic_fatha = 0x05ee, /* U+064E ARABIC FATHA */ + XK_Arabic_damma = 0x05ef, /* U+064F ARABIC DAMMA */ + XK_Arabic_kasra = 0x05f0, /* U+0650 ARABIC KASRA */ + XK_Arabic_shadda = 0x05f1, /* U+0651 ARABIC SHADDA */ + XK_Arabic_sukun = 0x05f2, /* U+0652 ARABIC SUKUN */ + XK_Arabic_madda_above = 0x1000653, /* U+0653 ARABIC MADDAH ABOVE */ + XK_Arabic_hamza_above = 0x1000654, /* U+0654 ARABIC HAMZA ABOVE */ + XK_Arabic_hamza_below = 0x1000655, /* U+0655 ARABIC HAMZA BELOW */ + XK_Arabic_jeh = 0x1000698, /* U+0698 ARABIC LETTER JEH */ + XK_Arabic_veh = 0x10006a4, /* U+06A4 ARABIC LETTER VEH */ + XK_Arabic_keheh = 0x10006a9, /* U+06A9 ARABIC LETTER KEHEH */ + XK_Arabic_gaf = 0x10006af, /* U+06AF ARABIC LETTER GAF */ + XK_Arabic_noon_ghunna = 0x10006ba, /* U+06BA ARABIC LETTER NOON GHUNNA */ + XK_Arabic_heh_doachashmee = 0x10006be, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */ + XK_Farsi_yeh = 0x10006cc, /* U+06CC ARABIC LETTER FARSI YEH */ + XK_Arabic_farsi_yeh = 0x10006cc, /* U+06CC ARABIC LETTER FARSI YEH */ + XK_Arabic_yeh_baree = 0x10006d2, /* U+06D2 ARABIC LETTER YEH BARREE */ + XK_Arabic_heh_goal = 0x10006c1, /* U+06C1 ARABIC LETTER HEH GOAL */ + XK_Arabic_switch = 0xff7e, /* Alias for mode_switch */ + XK_Cyrillic_GHE_bar = 0x1000492, /* U+0492 CYRILLIC CAPITAL LETTER GHE WITH STROKE */ + XK_Cyrillic_ghe_bar = 0x1000493, /* U+0493 CYRILLIC SMALL LETTER GHE WITH STROKE */ + XK_Cyrillic_ZHE_descender = 0x1000496, /* U+0496 CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */ + XK_Cyrillic_zhe_descender = 0x1000497, /* U+0497 CYRILLIC SMALL LETTER ZHE WITH DESCENDER */ + XK_Cyrillic_KA_descender = 0x100049a, /* U+049A CYRILLIC CAPITAL LETTER KA WITH DESCENDER */ + XK_Cyrillic_ka_descender = 0x100049b, /* U+049B CYRILLIC SMALL LETTER KA WITH DESCENDER */ + XK_Cyrillic_KA_vertstroke = 0x100049c, /* U+049C CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */ + XK_Cyrillic_ka_vertstroke = 0x100049d, /* U+049D CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE */ + XK_Cyrillic_EN_descender = 0x10004a2, /* U+04A2 CYRILLIC CAPITAL LETTER EN WITH DESCENDER */ + XK_Cyrillic_en_descender = 0x10004a3, /* U+04A3 CYRILLIC SMALL LETTER EN WITH DESCENDER */ + XK_Cyrillic_U_straight = 0x10004ae, /* U+04AE CYRILLIC CAPITAL LETTER STRAIGHT U */ + XK_Cyrillic_u_straight = 0x10004af, /* U+04AF CYRILLIC SMALL LETTER STRAIGHT U */ + XK_Cyrillic_U_straight_bar = 0x10004b0, /* U+04B0 CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */ + XK_Cyrillic_u_straight_bar = 0x10004b1, /* U+04B1 CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE */ + XK_Cyrillic_HA_descender = 0x10004b2, /* U+04B2 CYRILLIC CAPITAL LETTER HA WITH DESCENDER */ + XK_Cyrillic_ha_descender = 0x10004b3, /* U+04B3 CYRILLIC SMALL LETTER HA WITH DESCENDER */ + XK_Cyrillic_CHE_descender = 0x10004b6, /* U+04B6 CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */ + XK_Cyrillic_che_descender = 0x10004b7, /* U+04B7 CYRILLIC SMALL LETTER CHE WITH DESCENDER */ + XK_Cyrillic_CHE_vertstroke = 0x10004b8, /* U+04B8 CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */ + XK_Cyrillic_che_vertstroke = 0x10004b9, /* U+04B9 CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE */ + XK_Cyrillic_SHHA = 0x10004ba, /* U+04BA CYRILLIC CAPITAL LETTER SHHA */ + XK_Cyrillic_shha = 0x10004bb, /* U+04BB CYRILLIC SMALL LETTER SHHA */ + XK_Cyrillic_SCHWA = 0x10004d8, /* U+04D8 CYRILLIC CAPITAL LETTER SCHWA */ + XK_Cyrillic_schwa = 0x10004d9, /* U+04D9 CYRILLIC SMALL LETTER SCHWA */ + XK_Cyrillic_I_macron = 0x10004e2, /* U+04E2 CYRILLIC CAPITAL LETTER I WITH MACRON */ + XK_Cyrillic_i_macron = 0x10004e3, /* U+04E3 CYRILLIC SMALL LETTER I WITH MACRON */ + XK_Cyrillic_O_bar = 0x10004e8, /* U+04E8 CYRILLIC CAPITAL LETTER BARRED O */ + XK_Cyrillic_o_bar = 0x10004e9, /* U+04E9 CYRILLIC SMALL LETTER BARRED O */ + XK_Cyrillic_U_macron = 0x10004ee, /* U+04EE CYRILLIC CAPITAL LETTER U WITH MACRON */ + XK_Cyrillic_u_macron = 0x10004ef, /* U+04EF CYRILLIC SMALL LETTER U WITH MACRON */ + XK_Serbian_dje = 0x06a1, /* U+0452 CYRILLIC SMALL LETTER DJE */ + XK_Macedonia_gje = 0x06a2, /* U+0453 CYRILLIC SMALL LETTER GJE */ + XK_Cyrillic_io = 0x06a3, /* U+0451 CYRILLIC SMALL LETTER IO */ + XK_Ukrainian_ie = 0x06a4, /* U+0454 CYRILLIC SMALL LETTER UKRAINIAN IE */ + XK_Ukranian_je = 0x06a4, /* deprecated */ + XK_Macedonia_dse = 0x06a5, /* U+0455 CYRILLIC SMALL LETTER DZE */ + XK_Ukrainian_i = 0x06a6, /* U+0456 CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + XK_Ukranian_i = 0x06a6, /* deprecated */ + XK_Ukrainian_yi = 0x06a7, /* U+0457 CYRILLIC SMALL LETTER YI */ + XK_Ukranian_yi = 0x06a7, /* deprecated */ + XK_Cyrillic_je = 0x06a8, /* U+0458 CYRILLIC SMALL LETTER JE */ + XK_Serbian_je = 0x06a8, /* deprecated */ + XK_Cyrillic_lje = 0x06a9, /* U+0459 CYRILLIC SMALL LETTER LJE */ + XK_Serbian_lje = 0x06a9, /* deprecated */ + XK_Cyrillic_nje = 0x06aa, /* U+045A CYRILLIC SMALL LETTER NJE */ + XK_Serbian_nje = 0x06aa, /* deprecated */ + XK_Serbian_tshe = 0x06ab, /* U+045B CYRILLIC SMALL LETTER TSHE */ + XK_Macedonia_kje = 0x06ac, /* U+045C CYRILLIC SMALL LETTER KJE */ + XK_Ukrainian_ghe_with_upturn = 0x06ad, /* U+0491 CYRILLIC SMALL LETTER GHE WITH UPTURN */ + XK_Byelorussian_shortu = 0x06ae, /* U+045E CYRILLIC SMALL LETTER SHORT U */ + XK_Cyrillic_dzhe = 0x06af, /* U+045F CYRILLIC SMALL LETTER DZHE */ + XK_Serbian_dze = 0x06af, /* deprecated */ + XK_numerosign = 0x06b0, /* U+2116 NUMERO SIGN */ + XK_Serbian_DJE = 0x06b1, /* U+0402 CYRILLIC CAPITAL LETTER DJE */ + XK_Macedonia_GJE = 0x06b2, /* U+0403 CYRILLIC CAPITAL LETTER GJE */ + XK_Cyrillic_IO = 0x06b3, /* U+0401 CYRILLIC CAPITAL LETTER IO */ + XK_Ukrainian_IE = 0x06b4, /* U+0404 CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + XK_Ukranian_JE = 0x06b4, /* deprecated */ + XK_Macedonia_DSE = 0x06b5, /* U+0405 CYRILLIC CAPITAL LETTER DZE */ + XK_Ukrainian_I = 0x06b6, /* U+0406 CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + XK_Ukranian_I = 0x06b6, /* deprecated */ + XK_Ukrainian_YI = 0x06b7, /* U+0407 CYRILLIC CAPITAL LETTER YI */ + XK_Ukranian_YI = 0x06b7, /* deprecated */ + XK_Cyrillic_JE = 0x06b8, /* U+0408 CYRILLIC CAPITAL LETTER JE */ + XK_Serbian_JE = 0x06b8, /* deprecated */ + XK_Cyrillic_LJE = 0x06b9, /* U+0409 CYRILLIC CAPITAL LETTER LJE */ + XK_Serbian_LJE = 0x06b9, /* deprecated */ + XK_Cyrillic_NJE = 0x06ba, /* U+040A CYRILLIC CAPITAL LETTER NJE */ + XK_Serbian_NJE = 0x06ba, /* deprecated */ + XK_Serbian_TSHE = 0x06bb, /* U+040B CYRILLIC CAPITAL LETTER TSHE */ + XK_Macedonia_KJE = 0x06bc, /* U+040C CYRILLIC CAPITAL LETTER KJE */ + XK_Ukrainian_GHE_WITH_UPTURN = 0x06bd, /* U+0490 CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ + XK_Byelorussian_SHORTU = 0x06be, /* U+040E CYRILLIC CAPITAL LETTER SHORT U */ + XK_Cyrillic_DZHE = 0x06bf, /* U+040F CYRILLIC CAPITAL LETTER DZHE */ + XK_Serbian_DZE = 0x06bf, /* deprecated */ + XK_Cyrillic_yu = 0x06c0, /* U+044E CYRILLIC SMALL LETTER YU */ + XK_Cyrillic_a = 0x06c1, /* U+0430 CYRILLIC SMALL LETTER A */ + XK_Cyrillic_be = 0x06c2, /* U+0431 CYRILLIC SMALL LETTER BE */ + XK_Cyrillic_tse = 0x06c3, /* U+0446 CYRILLIC SMALL LETTER TSE */ + XK_Cyrillic_de = 0x06c4, /* U+0434 CYRILLIC SMALL LETTER DE */ + XK_Cyrillic_ie = 0x06c5, /* U+0435 CYRILLIC SMALL LETTER IE */ + XK_Cyrillic_ef = 0x06c6, /* U+0444 CYRILLIC SMALL LETTER EF */ + XK_Cyrillic_ghe = 0x06c7, /* U+0433 CYRILLIC SMALL LETTER GHE */ + XK_Cyrillic_ha = 0x06c8, /* U+0445 CYRILLIC SMALL LETTER HA */ + XK_Cyrillic_i = 0x06c9, /* U+0438 CYRILLIC SMALL LETTER I */ + XK_Cyrillic_shorti = 0x06ca, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ + XK_Cyrillic_ka = 0x06cb, /* U+043A CYRILLIC SMALL LETTER KA */ + XK_Cyrillic_el = 0x06cc, /* U+043B CYRILLIC SMALL LETTER EL */ + XK_Cyrillic_em = 0x06cd, /* U+043C CYRILLIC SMALL LETTER EM */ + XK_Cyrillic_en = 0x06ce, /* U+043D CYRILLIC SMALL LETTER EN */ + XK_Cyrillic_o = 0x06cf, /* U+043E CYRILLIC SMALL LETTER O */ + XK_Cyrillic_pe = 0x06d0, /* U+043F CYRILLIC SMALL LETTER PE */ + XK_Cyrillic_ya = 0x06d1, /* U+044F CYRILLIC SMALL LETTER YA */ + XK_Cyrillic_er = 0x06d2, /* U+0440 CYRILLIC SMALL LETTER ER */ + XK_Cyrillic_es = 0x06d3, /* U+0441 CYRILLIC SMALL LETTER ES */ + XK_Cyrillic_te = 0x06d4, /* U+0442 CYRILLIC SMALL LETTER TE */ + XK_Cyrillic_u = 0x06d5, /* U+0443 CYRILLIC SMALL LETTER U */ + XK_Cyrillic_zhe = 0x06d6, /* U+0436 CYRILLIC SMALL LETTER ZHE */ + XK_Cyrillic_ve = 0x06d7, /* U+0432 CYRILLIC SMALL LETTER VE */ + XK_Cyrillic_softsign = 0x06d8, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ + XK_Cyrillic_yeru = 0x06d9, /* U+044B CYRILLIC SMALL LETTER YERU */ + XK_Cyrillic_ze = 0x06da, /* U+0437 CYRILLIC SMALL LETTER ZE */ + XK_Cyrillic_sha = 0x06db, /* U+0448 CYRILLIC SMALL LETTER SHA */ + XK_Cyrillic_e = 0x06dc, /* U+044D CYRILLIC SMALL LETTER E */ + XK_Cyrillic_shcha = 0x06dd, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ + XK_Cyrillic_che = 0x06de, /* U+0447 CYRILLIC SMALL LETTER CHE */ + XK_Cyrillic_hardsign = 0x06df, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ + XK_Cyrillic_YU = 0x06e0, /* U+042E CYRILLIC CAPITAL LETTER YU */ + XK_Cyrillic_A = 0x06e1, /* U+0410 CYRILLIC CAPITAL LETTER A */ + XK_Cyrillic_BE = 0x06e2, /* U+0411 CYRILLIC CAPITAL LETTER BE */ + XK_Cyrillic_TSE = 0x06e3, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ + XK_Cyrillic_DE = 0x06e4, /* U+0414 CYRILLIC CAPITAL LETTER DE */ + XK_Cyrillic_IE = 0x06e5, /* U+0415 CYRILLIC CAPITAL LETTER IE */ + XK_Cyrillic_EF = 0x06e6, /* U+0424 CYRILLIC CAPITAL LETTER EF */ + XK_Cyrillic_GHE = 0x06e7, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ + XK_Cyrillic_HA = 0x06e8, /* U+0425 CYRILLIC CAPITAL LETTER HA */ + XK_Cyrillic_I = 0x06e9, /* U+0418 CYRILLIC CAPITAL LETTER I */ + XK_Cyrillic_SHORTI = 0x06ea, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ + XK_Cyrillic_KA = 0x06eb, /* U+041A CYRILLIC CAPITAL LETTER KA */ + XK_Cyrillic_EL = 0x06ec, /* U+041B CYRILLIC CAPITAL LETTER EL */ + XK_Cyrillic_EM = 0x06ed, /* U+041C CYRILLIC CAPITAL LETTER EM */ + XK_Cyrillic_EN = 0x06ee, /* U+041D CYRILLIC CAPITAL LETTER EN */ + XK_Cyrillic_O = 0x06ef, /* U+041E CYRILLIC CAPITAL LETTER O */ + XK_Cyrillic_PE = 0x06f0, /* U+041F CYRILLIC CAPITAL LETTER PE */ + XK_Cyrillic_YA = 0x06f1, /* U+042F CYRILLIC CAPITAL LETTER YA */ + XK_Cyrillic_ER = 0x06f2, /* U+0420 CYRILLIC CAPITAL LETTER ER */ + XK_Cyrillic_ES = 0x06f3, /* U+0421 CYRILLIC CAPITAL LETTER ES */ + XK_Cyrillic_TE = 0x06f4, /* U+0422 CYRILLIC CAPITAL LETTER TE */ + XK_Cyrillic_U = 0x06f5, /* U+0423 CYRILLIC CAPITAL LETTER U */ + XK_Cyrillic_ZHE = 0x06f6, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ + XK_Cyrillic_VE = 0x06f7, /* U+0412 CYRILLIC CAPITAL LETTER VE */ + XK_Cyrillic_SOFTSIGN = 0x06f8, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ + XK_Cyrillic_YERU = 0x06f9, /* U+042B CYRILLIC CAPITAL LETTER YERU */ + XK_Cyrillic_ZE = 0x06fa, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ + XK_Cyrillic_SHA = 0x06fb, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ + XK_Cyrillic_E = 0x06fc, /* U+042D CYRILLIC CAPITAL LETTER E */ + XK_Cyrillic_SHCHA = 0x06fd, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ + XK_Cyrillic_CHE = 0x06fe, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ + XK_Cyrillic_HARDSIGN = 0x06ff, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ + XK_Greek_ALPHAaccent = 0x07a1, /* U+0386 GREEK CAPITAL LETTER ALPHA WITH TONOS */ + XK_Greek_EPSILONaccent = 0x07a2, /* U+0388 GREEK CAPITAL LETTER EPSILON WITH TONOS */ + XK_Greek_ETAaccent = 0x07a3, /* U+0389 GREEK CAPITAL LETTER ETA WITH TONOS */ + XK_Greek_IOTAaccent = 0x07a4, /* U+038A GREEK CAPITAL LETTER IOTA WITH TONOS */ + XK_Greek_IOTAdieresis = 0x07a5, /* U+03AA GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + XK_Greek_IOTAdiaeresis = 0x07a5, /* old typo */ + XK_Greek_OMICRONaccent = 0x07a7, /* U+038C GREEK CAPITAL LETTER OMICRON WITH TONOS */ + XK_Greek_UPSILONaccent = 0x07a8, /* U+038E GREEK CAPITAL LETTER UPSILON WITH TONOS */ + XK_Greek_UPSILONdieresis = 0x07a9, /* U+03AB GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + XK_Greek_OMEGAaccent = 0x07ab, /* U+038F GREEK CAPITAL LETTER OMEGA WITH TONOS */ + XK_Greek_accentdieresis = 0x07ae, /* U+0385 GREEK DIALYTIKA TONOS */ + XK_Greek_horizbar = 0x07af, /* U+2015 HORIZONTAL BAR */ + XK_Greek_alphaaccent = 0x07b1, /* U+03AC GREEK SMALL LETTER ALPHA WITH TONOS */ + XK_Greek_epsilonaccent = 0x07b2, /* U+03AD GREEK SMALL LETTER EPSILON WITH TONOS */ + XK_Greek_etaaccent = 0x07b3, /* U+03AE GREEK SMALL LETTER ETA WITH TONOS */ + XK_Greek_iotaaccent = 0x07b4, /* U+03AF GREEK SMALL LETTER IOTA WITH TONOS */ + XK_Greek_iotadieresis = 0x07b5, /* U+03CA GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + XK_Greek_iotaaccentdieresis = 0x07b6, /* U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + XK_Greek_omicronaccent = 0x07b7, /* U+03CC GREEK SMALL LETTER OMICRON WITH TONOS */ + XK_Greek_upsilonaccent = 0x07b8, /* U+03CD GREEK SMALL LETTER UPSILON WITH TONOS */ + XK_Greek_upsilondieresis = 0x07b9, /* U+03CB GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + XK_Greek_upsilonaccentdieresis = 0x07ba, /* U+03B0 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + XK_Greek_omegaaccent = 0x07bb, /* U+03CE GREEK SMALL LETTER OMEGA WITH TONOS */ + XK_Greek_ALPHA = 0x07c1, /* U+0391 GREEK CAPITAL LETTER ALPHA */ + XK_Greek_BETA = 0x07c2, /* U+0392 GREEK CAPITAL LETTER BETA */ + XK_Greek_GAMMA = 0x07c3, /* U+0393 GREEK CAPITAL LETTER GAMMA */ + XK_Greek_DELTA = 0x07c4, /* U+0394 GREEK CAPITAL LETTER DELTA */ + XK_Greek_EPSILON = 0x07c5, /* U+0395 GREEK CAPITAL LETTER EPSILON */ + XK_Greek_ZETA = 0x07c6, /* U+0396 GREEK CAPITAL LETTER ZETA */ + XK_Greek_ETA = 0x07c7, /* U+0397 GREEK CAPITAL LETTER ETA */ + XK_Greek_THETA = 0x07c8, /* U+0398 GREEK CAPITAL LETTER THETA */ + XK_Greek_IOTA = 0x07c9, /* U+0399 GREEK CAPITAL LETTER IOTA */ + XK_Greek_KAPPA = 0x07ca, /* U+039A GREEK CAPITAL LETTER KAPPA */ + XK_Greek_LAMDA = 0x07cb, /* U+039B GREEK CAPITAL LETTER LAMDA */ + XK_Greek_LAMBDA = 0x07cb, /* U+039B GREEK CAPITAL LETTER LAMDA */ + XK_Greek_MU = 0x07cc, /* U+039C GREEK CAPITAL LETTER MU */ + XK_Greek_NU = 0x07cd, /* U+039D GREEK CAPITAL LETTER NU */ + XK_Greek_XI = 0x07ce, /* U+039E GREEK CAPITAL LETTER XI */ + XK_Greek_OMICRON = 0x07cf, /* U+039F GREEK CAPITAL LETTER OMICRON */ + XK_Greek_PI = 0x07d0, /* U+03A0 GREEK CAPITAL LETTER PI */ + XK_Greek_RHO = 0x07d1, /* U+03A1 GREEK CAPITAL LETTER RHO */ + XK_Greek_SIGMA = 0x07d2, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ + XK_Greek_TAU = 0x07d4, /* U+03A4 GREEK CAPITAL LETTER TAU */ + XK_Greek_UPSILON = 0x07d5, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ + XK_Greek_PHI = 0x07d6, /* U+03A6 GREEK CAPITAL LETTER PHI */ + XK_Greek_CHI = 0x07d7, /* U+03A7 GREEK CAPITAL LETTER CHI */ + XK_Greek_PSI = 0x07d8, /* U+03A8 GREEK CAPITAL LETTER PSI */ + XK_Greek_OMEGA = 0x07d9, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ + XK_Greek_alpha = 0x07e1, /* U+03B1 GREEK SMALL LETTER ALPHA */ + XK_Greek_beta = 0x07e2, /* U+03B2 GREEK SMALL LETTER BETA */ + XK_Greek_gamma = 0x07e3, /* U+03B3 GREEK SMALL LETTER GAMMA */ + XK_Greek_delta = 0x07e4, /* U+03B4 GREEK SMALL LETTER DELTA */ + XK_Greek_epsilon = 0x07e5, /* U+03B5 GREEK SMALL LETTER EPSILON */ + XK_Greek_zeta = 0x07e6, /* U+03B6 GREEK SMALL LETTER ZETA */ + XK_Greek_eta = 0x07e7, /* U+03B7 GREEK SMALL LETTER ETA */ + XK_Greek_theta = 0x07e8, /* U+03B8 GREEK SMALL LETTER THETA */ + XK_Greek_iota = 0x07e9, /* U+03B9 GREEK SMALL LETTER IOTA */ + XK_Greek_kappa = 0x07ea, /* U+03BA GREEK SMALL LETTER KAPPA */ + XK_Greek_lamda = 0x07eb, /* U+03BB GREEK SMALL LETTER LAMDA */ + XK_Greek_lambda = 0x07eb, /* U+03BB GREEK SMALL LETTER LAMDA */ + XK_Greek_mu = 0x07ec, /* U+03BC GREEK SMALL LETTER MU */ + XK_Greek_nu = 0x07ed, /* U+03BD GREEK SMALL LETTER NU */ + XK_Greek_xi = 0x07ee, /* U+03BE GREEK SMALL LETTER XI */ + XK_Greek_omicron = 0x07ef, /* U+03BF GREEK SMALL LETTER OMICRON */ + XK_Greek_pi = 0x07f0, /* U+03C0 GREEK SMALL LETTER PI */ + XK_Greek_rho = 0x07f1, /* U+03C1 GREEK SMALL LETTER RHO */ + XK_Greek_sigma = 0x07f2, /* U+03C3 GREEK SMALL LETTER SIGMA */ + XK_Greek_finalsmallsigma = 0x07f3, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA */ + XK_Greek_tau = 0x07f4, /* U+03C4 GREEK SMALL LETTER TAU */ + XK_Greek_upsilon = 0x07f5, /* U+03C5 GREEK SMALL LETTER UPSILON */ + XK_Greek_phi = 0x07f6, /* U+03C6 GREEK SMALL LETTER PHI */ + XK_Greek_chi = 0x07f7, /* U+03C7 GREEK SMALL LETTER CHI */ + XK_Greek_psi = 0x07f8, /* U+03C8 GREEK SMALL LETTER PSI */ + XK_Greek_omega = 0x07f9, /* U+03C9 GREEK SMALL LETTER OMEGA */ + XK_Greek_switch = 0xff7e, /* Alias for mode_switch */ + XK_leftradical = 0x08a1, /* U+23B7 RADICAL SYMBOL BOTTOM */ + XK_topleftradical = 0x08a2, /*(U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT)*/ + XK_horizconnector = 0x08a3, /*(U+2500 BOX DRAWINGS LIGHT HORIZONTAL)*/ + XK_topintegral = 0x08a4, /* U+2320 TOP HALF INTEGRAL */ + XK_botintegral = 0x08a5, /* U+2321 BOTTOM HALF INTEGRAL */ + XK_vertconnector = 0x08a6, /*(U+2502 BOX DRAWINGS LIGHT VERTICAL)*/ + XK_topleftsqbracket = 0x08a7, /* U+23A1 LEFT SQUARE BRACKET UPPER CORNER */ + XK_botleftsqbracket = 0x08a8, /* U+23A3 LEFT SQUARE BRACKET LOWER CORNER */ + XK_toprightsqbracket = 0x08a9, /* U+23A4 RIGHT SQUARE BRACKET UPPER CORNER */ + XK_botrightsqbracket = 0x08aa, /* U+23A6 RIGHT SQUARE BRACKET LOWER CORNER */ + XK_topleftparens = 0x08ab, /* U+239B LEFT PARENTHESIS UPPER HOOK */ + XK_botleftparens = 0x08ac, /* U+239D LEFT PARENTHESIS LOWER HOOK */ + XK_toprightparens = 0x08ad, /* U+239E RIGHT PARENTHESIS UPPER HOOK */ + XK_botrightparens = 0x08ae, /* U+23A0 RIGHT PARENTHESIS LOWER HOOK */ + XK_leftmiddlecurlybrace = 0x08af, /* U+23A8 LEFT CURLY BRACKET MIDDLE PIECE */ + XK_rightmiddlecurlybrace = 0x08b0, /* U+23AC RIGHT CURLY BRACKET MIDDLE PIECE */ + XK_topleftsummation = 0x08b1, + XK_botleftsummation = 0x08b2, + XK_topvertsummationconnector = 0x08b3, + XK_botvertsummationconnector = 0x08b4, + XK_toprightsummation = 0x08b5, + XK_botrightsummation = 0x08b6, + XK_rightmiddlesummation = 0x08b7, + XK_lessthanequal = 0x08bc, /* U+2264 LESS-THAN OR EQUAL TO */ + XK_notequal = 0x08bd, /* U+2260 NOT EQUAL TO */ + XK_greaterthanequal = 0x08be, /* U+2265 GREATER-THAN OR EQUAL TO */ + XK_integral = 0x08bf, /* U+222B INTEGRAL */ + XK_therefore = 0x08c0, /* U+2234 THEREFORE */ + XK_variation = 0x08c1, /* U+221D PROPORTIONAL TO */ + XK_infinity = 0x08c2, /* U+221E INFINITY */ + XK_nabla = 0x08c5, /* U+2207 NABLA */ + XK_approximate = 0x08c8, /* U+223C TILDE OPERATOR */ + XK_similarequal = 0x08c9, /* U+2243 ASYMPTOTICALLY EQUAL TO */ + XK_ifonlyif = 0x08cd, /* U+21D4 LEFT RIGHT DOUBLE ARROW */ + XK_implies = 0x08ce, /* U+21D2 RIGHTWARDS DOUBLE ARROW */ + XK_identical = 0x08cf, /* U+2261 IDENTICAL TO */ + XK_radical = 0x08d6, /* U+221A SQUARE ROOT */ + XK_includedin = 0x08da, /* U+2282 SUBSET OF */ + XK_includes = 0x08db, /* U+2283 SUPERSET OF */ + XK_intersection = 0x08dc, /* U+2229 INTERSECTION */ + XK_union = 0x08dd, /* U+222A UNION */ + XK_logicaland = 0x08de, /* U+2227 LOGICAL AND */ + XK_logicalor = 0x08df, /* U+2228 LOGICAL OR */ + XK_partialderivative = 0x08ef, /* U+2202 PARTIAL DIFFERENTIAL */ + XK_function = 0x08f6, /* U+0192 LATIN SMALL LETTER F WITH HOOK */ + XK_leftarrow = 0x08fb, /* U+2190 LEFTWARDS ARROW */ + XK_uparrow = 0x08fc, /* U+2191 UPWARDS ARROW */ + XK_rightarrow = 0x08fd, /* U+2192 RIGHTWARDS ARROW */ + XK_downarrow = 0x08fe, /* U+2193 DOWNWARDS ARROW */ + XK_blank = 0x09df, + XK_soliddiamond = 0x09e0, /* U+25C6 BLACK DIAMOND */ + XK_checkerboard = 0x09e1, /* U+2592 MEDIUM SHADE */ + XK_ht = 0x09e2, /* U+2409 SYMBOL FOR HORIZONTAL TABULATION */ + XK_ff = 0x09e3, /* U+240C SYMBOL FOR FORM FEED */ + XK_cr = 0x09e4, /* U+240D SYMBOL FOR CARRIAGE RETURN */ + XK_lf = 0x09e5, /* U+240A SYMBOL FOR LINE FEED */ + XK_nl = 0x09e8, /* U+2424 SYMBOL FOR NEWLINE */ + XK_vt = 0x09e9, /* U+240B SYMBOL FOR VERTICAL TABULATION */ + XK_lowrightcorner = 0x09ea, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT */ + XK_uprightcorner = 0x09eb, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT */ + XK_upleftcorner = 0x09ec, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT */ + XK_lowleftcorner = 0x09ed, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT */ + XK_crossinglines = 0x09ee, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + XK_horizlinescan1 = 0x09ef, /* U+23BA HORIZONTAL SCAN LINE-1 */ + XK_horizlinescan3 = 0x09f0, /* U+23BB HORIZONTAL SCAN LINE-3 */ + XK_horizlinescan5 = 0x09f1, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL */ + XK_horizlinescan7 = 0x09f2, /* U+23BC HORIZONTAL SCAN LINE-7 */ + XK_horizlinescan9 = 0x09f3, /* U+23BD HORIZONTAL SCAN LINE-9 */ + XK_leftt = 0x09f4, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + XK_rightt = 0x09f5, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + XK_bott = 0x09f6, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + XK_topt = 0x09f7, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + XK_vertbar = 0x09f8, /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ + XK_emspace = 0x0aa1, /* U+2003 EM SPACE */ + XK_enspace = 0x0aa2, /* U+2002 EN SPACE */ + XK_em3space = 0x0aa3, /* U+2004 THREE-PER-EM SPACE */ + XK_em4space = 0x0aa4, /* U+2005 FOUR-PER-EM SPACE */ + XK_digitspace = 0x0aa5, /* U+2007 FIGURE SPACE */ + XK_punctspace = 0x0aa6, /* U+2008 PUNCTUATION SPACE */ + XK_thinspace = 0x0aa7, /* U+2009 THIN SPACE */ + XK_hairspace = 0x0aa8, /* U+200A HAIR SPACE */ + XK_emdash = 0x0aa9, /* U+2014 EM DASH */ + XK_endash = 0x0aaa, /* U+2013 EN DASH */ + XK_signifblank = 0x0aac, /*(U+2423 OPEN BOX)*/ + XK_ellipsis = 0x0aae, /* U+2026 HORIZONTAL ELLIPSIS */ + XK_doubbaselinedot = 0x0aaf, /* U+2025 TWO DOT LEADER */ + XK_onethird = 0x0ab0, /* U+2153 VULGAR FRACTION ONE THIRD */ + XK_twothirds = 0x0ab1, /* U+2154 VULGAR FRACTION TWO THIRDS */ + XK_onefifth = 0x0ab2, /* U+2155 VULGAR FRACTION ONE FIFTH */ + XK_twofifths = 0x0ab3, /* U+2156 VULGAR FRACTION TWO FIFTHS */ + XK_threefifths = 0x0ab4, /* U+2157 VULGAR FRACTION THREE FIFTHS */ + XK_fourfifths = 0x0ab5, /* U+2158 VULGAR FRACTION FOUR FIFTHS */ + XK_onesixth = 0x0ab6, /* U+2159 VULGAR FRACTION ONE SIXTH */ + XK_fivesixths = 0x0ab7, /* U+215A VULGAR FRACTION FIVE SIXTHS */ + XK_careof = 0x0ab8, /* U+2105 CARE OF */ + XK_figdash = 0x0abb, /* U+2012 FIGURE DASH */ + XK_leftanglebracket = 0x0abc, /*(U+27E8 MATHEMATICAL LEFT ANGLE BRACKET)*/ + XK_decimalpoint = 0x0abd, /*(U+002E FULL STOP)*/ + XK_rightanglebracket = 0x0abe, /*(U+27E9 MATHEMATICAL RIGHT ANGLE BRACKET)*/ + XK_marker = 0x0abf, + XK_oneeighth = 0x0ac3, /* U+215B VULGAR FRACTION ONE EIGHTH */ + XK_threeeighths = 0x0ac4, /* U+215C VULGAR FRACTION THREE EIGHTHS */ + XK_fiveeighths = 0x0ac5, /* U+215D VULGAR FRACTION FIVE EIGHTHS */ + XK_seveneighths = 0x0ac6, /* U+215E VULGAR FRACTION SEVEN EIGHTHS */ + XK_trademark = 0x0ac9, /* U+2122 TRADE MARK SIGN */ + XK_signaturemark = 0x0aca, /*(U+2613 SALTIRE)*/ + XK_trademarkincircle = 0x0acb, + XK_leftopentriangle = 0x0acc, /*(U+25C1 WHITE LEFT-POINTING TRIANGLE)*/ + XK_rightopentriangle = 0x0acd, /*(U+25B7 WHITE RIGHT-POINTING TRIANGLE)*/ + XK_emopencircle = 0x0ace, /*(U+25CB WHITE CIRCLE)*/ + XK_emopenrectangle = 0x0acf, /*(U+25AF WHITE VERTICAL RECTANGLE)*/ + XK_leftsinglequotemark = 0x0ad0, /* U+2018 LEFT SINGLE QUOTATION MARK */ + XK_rightsinglequotemark = 0x0ad1, /* U+2019 RIGHT SINGLE QUOTATION MARK */ + XK_leftdoublequotemark = 0x0ad2, /* U+201C LEFT DOUBLE QUOTATION MARK */ + XK_rightdoublequotemark = 0x0ad3, /* U+201D RIGHT DOUBLE QUOTATION MARK */ + XK_prescription = 0x0ad4, /* U+211E PRESCRIPTION TAKE */ + XK_minutes = 0x0ad6, /* U+2032 PRIME */ + XK_seconds = 0x0ad7, /* U+2033 DOUBLE PRIME */ + XK_latincross = 0x0ad9, /* U+271D LATIN CROSS */ + XK_hexagram = 0x0ada, + XK_filledrectbullet = 0x0adb, /*(U+25AC BLACK RECTANGLE)*/ + XK_filledlefttribullet = 0x0adc, /*(U+25C0 BLACK LEFT-POINTING TRIANGLE)*/ + XK_filledrighttribullet = 0x0add, /*(U+25B6 BLACK RIGHT-POINTING TRIANGLE)*/ + XK_emfilledcircle = 0x0ade, /*(U+25CF BLACK CIRCLE)*/ + XK_emfilledrect = 0x0adf, /*(U+25AE BLACK VERTICAL RECTANGLE)*/ + XK_enopencircbullet = 0x0ae0, /*(U+25E6 WHITE BULLET)*/ + XK_enopensquarebullet = 0x0ae1, /*(U+25AB WHITE SMALL SQUARE)*/ + XK_openrectbullet = 0x0ae2, /*(U+25AD WHITE RECTANGLE)*/ + XK_opentribulletup = 0x0ae3, /*(U+25B3 WHITE UP-POINTING TRIANGLE)*/ + XK_opentribulletdown = 0x0ae4, /*(U+25BD WHITE DOWN-POINTING TRIANGLE)*/ + XK_openstar = 0x0ae5, /*(U+2606 WHITE STAR)*/ + XK_enfilledcircbullet = 0x0ae6, /*(U+2022 BULLET)*/ + XK_enfilledsqbullet = 0x0ae7, /*(U+25AA BLACK SMALL SQUARE)*/ + XK_filledtribulletup = 0x0ae8, /*(U+25B2 BLACK UP-POINTING TRIANGLE)*/ + XK_filledtribulletdown = 0x0ae9, /*(U+25BC BLACK DOWN-POINTING TRIANGLE)*/ + XK_leftpointer = 0x0aea, /*(U+261C WHITE LEFT POINTING INDEX)*/ + XK_rightpointer = 0x0aeb, /*(U+261E WHITE RIGHT POINTING INDEX)*/ + XK_club = 0x0aec, /* U+2663 BLACK CLUB SUIT */ + XK_diamond = 0x0aed, /* U+2666 BLACK DIAMOND SUIT */ + XK_heart = 0x0aee, /* U+2665 BLACK HEART SUIT */ + XK_maltesecross = 0x0af0, /* U+2720 MALTESE CROSS */ + XK_dagger = 0x0af1, /* U+2020 DAGGER */ + XK_doubledagger = 0x0af2, /* U+2021 DOUBLE DAGGER */ + XK_checkmark = 0x0af3, /* U+2713 CHECK MARK */ + XK_ballotcross = 0x0af4, /* U+2717 BALLOT X */ + XK_musicalsharp = 0x0af5, /* U+266F MUSIC SHARP SIGN */ + XK_musicalflat = 0x0af6, /* U+266D MUSIC FLAT SIGN */ + XK_malesymbol = 0x0af7, /* U+2642 MALE SIGN */ + XK_femalesymbol = 0x0af8, /* U+2640 FEMALE SIGN */ + XK_telephone = 0x0af9, /* U+260E BLACK TELEPHONE */ + XK_telephonerecorder = 0x0afa, /* U+2315 TELEPHONE RECORDER */ + XK_phonographcopyright = 0x0afb, /* U+2117 SOUND RECORDING COPYRIGHT */ + XK_caret = 0x0afc, /* U+2038 CARET */ + XK_singlelowquotemark = 0x0afd, /* U+201A SINGLE LOW-9 QUOTATION MARK */ + XK_doublelowquotemark = 0x0afe, /* U+201E DOUBLE LOW-9 QUOTATION MARK */ + XK_cursor = 0x0aff, + XK_leftcaret = 0x0ba3, /*(U+003C LESS-THAN SIGN)*/ + XK_rightcaret = 0x0ba6, /*(U+003E GREATER-THAN SIGN)*/ + XK_downcaret = 0x0ba8, /*(U+2228 LOGICAL OR)*/ + XK_upcaret = 0x0ba9, /*(U+2227 LOGICAL AND)*/ + XK_overbar = 0x0bc0, /*(U+00AF MACRON)*/ + XK_downtack = 0x0bc2, /* U+22A5 UP TACK */ + XK_upshoe = 0x0bc3, /*(U+2229 INTERSECTION)*/ + XK_downstile = 0x0bc4, /* U+230A LEFT FLOOR */ + XK_underbar = 0x0bc6, /*(U+005F LOW LINE)*/ + XK_jot = 0x0bca, /* U+2218 RING OPERATOR */ + XK_quad = 0x0bcc, /* U+2395 APL FUNCTIONAL SYMBOL QUAD */ + XK_uptack = 0x0bce, /* U+22A4 DOWN TACK */ + XK_circle = 0x0bcf, /* U+25CB WHITE CIRCLE */ + XK_upstile = 0x0bd3, /* U+2308 LEFT CEILING */ + XK_downshoe = 0x0bd6, /*(U+222A UNION)*/ + XK_rightshoe = 0x0bd8, /*(U+2283 SUPERSET OF)*/ + XK_leftshoe = 0x0bda, /*(U+2282 SUBSET OF)*/ + XK_lefttack = 0x0bdc, /* U+22A2 RIGHT TACK */ + XK_righttack = 0x0bfc, /* U+22A3 LEFT TACK */ + XK_hebrew_doublelowline = 0x0cdf, /* U+2017 DOUBLE LOW LINE */ + XK_hebrew_aleph = 0x0ce0, /* U+05D0 HEBREW LETTER ALEF */ + XK_hebrew_bet = 0x0ce1, /* U+05D1 HEBREW LETTER BET */ + XK_hebrew_beth = 0x0ce1, /* deprecated */ + XK_hebrew_gimel = 0x0ce2, /* U+05D2 HEBREW LETTER GIMEL */ + XK_hebrew_gimmel = 0x0ce2, /* deprecated */ + XK_hebrew_dalet = 0x0ce3, /* U+05D3 HEBREW LETTER DALET */ + XK_hebrew_daleth = 0x0ce3, /* deprecated */ + XK_hebrew_he = 0x0ce4, /* U+05D4 HEBREW LETTER HE */ + XK_hebrew_waw = 0x0ce5, /* U+05D5 HEBREW LETTER VAV */ + XK_hebrew_zain = 0x0ce6, /* U+05D6 HEBREW LETTER ZAYIN */ + XK_hebrew_zayin = 0x0ce6, /* deprecated */ + XK_hebrew_chet = 0x0ce7, /* U+05D7 HEBREW LETTER HET */ + XK_hebrew_het = 0x0ce7, /* deprecated */ + XK_hebrew_tet = 0x0ce8, /* U+05D8 HEBREW LETTER TET */ + XK_hebrew_teth = 0x0ce8, /* deprecated */ + XK_hebrew_yod = 0x0ce9, /* U+05D9 HEBREW LETTER YOD */ + XK_hebrew_finalkaph = 0x0cea, /* U+05DA HEBREW LETTER FINAL KAF */ + XK_hebrew_kaph = 0x0ceb, /* U+05DB HEBREW LETTER KAF */ + XK_hebrew_lamed = 0x0cec, /* U+05DC HEBREW LETTER LAMED */ + XK_hebrew_finalmem = 0x0ced, /* U+05DD HEBREW LETTER FINAL MEM */ + XK_hebrew_mem = 0x0cee, /* U+05DE HEBREW LETTER MEM */ + XK_hebrew_finalnun = 0x0cef, /* U+05DF HEBREW LETTER FINAL NUN */ + XK_hebrew_nun = 0x0cf0, /* U+05E0 HEBREW LETTER NUN */ + XK_hebrew_samech = 0x0cf1, /* U+05E1 HEBREW LETTER SAMEKH */ + XK_hebrew_samekh = 0x0cf1, /* deprecated */ + XK_hebrew_ayin = 0x0cf2, /* U+05E2 HEBREW LETTER AYIN */ + XK_hebrew_finalpe = 0x0cf3, /* U+05E3 HEBREW LETTER FINAL PE */ + XK_hebrew_pe = 0x0cf4, /* U+05E4 HEBREW LETTER PE */ + XK_hebrew_finalzade = 0x0cf5, /* U+05E5 HEBREW LETTER FINAL TSADI */ + XK_hebrew_finalzadi = 0x0cf5, /* deprecated */ + XK_hebrew_zade = 0x0cf6, /* U+05E6 HEBREW LETTER TSADI */ + XK_hebrew_zadi = 0x0cf6, /* deprecated */ + XK_hebrew_qoph = 0x0cf7, /* U+05E7 HEBREW LETTER QOF */ + XK_hebrew_kuf = 0x0cf7, /* deprecated */ + XK_hebrew_resh = 0x0cf8, /* U+05E8 HEBREW LETTER RESH */ + XK_hebrew_shin = 0x0cf9, /* U+05E9 HEBREW LETTER SHIN */ + XK_hebrew_taw = 0x0cfa, /* U+05EA HEBREW LETTER TAV */ + XK_hebrew_taf = 0x0cfa, /* deprecated */ + XK_Hebrew_switch = 0xff7e, /* Alias for mode_switch */ + XK_Thai_kokai = 0x0da1, /* U+0E01 THAI CHARACTER KO KAI */ + XK_Thai_khokhai = 0x0da2, /* U+0E02 THAI CHARACTER KHO KHAI */ + XK_Thai_khokhuat = 0x0da3, /* U+0E03 THAI CHARACTER KHO KHUAT */ + XK_Thai_khokhwai = 0x0da4, /* U+0E04 THAI CHARACTER KHO KHWAI */ + XK_Thai_khokhon = 0x0da5, /* U+0E05 THAI CHARACTER KHO KHON */ + XK_Thai_khorakhang = 0x0da6, /* U+0E06 THAI CHARACTER KHO RAKHANG */ + XK_Thai_ngongu = 0x0da7, /* U+0E07 THAI CHARACTER NGO NGU */ + XK_Thai_chochan = 0x0da8, /* U+0E08 THAI CHARACTER CHO CHAN */ + XK_Thai_choching = 0x0da9, /* U+0E09 THAI CHARACTER CHO CHING */ + XK_Thai_chochang = 0x0daa, /* U+0E0A THAI CHARACTER CHO CHANG */ + XK_Thai_soso = 0x0dab, /* U+0E0B THAI CHARACTER SO SO */ + XK_Thai_chochoe = 0x0dac, /* U+0E0C THAI CHARACTER CHO CHOE */ + XK_Thai_yoying = 0x0dad, /* U+0E0D THAI CHARACTER YO YING */ + XK_Thai_dochada = 0x0dae, /* U+0E0E THAI CHARACTER DO CHADA */ + XK_Thai_topatak = 0x0daf, /* U+0E0F THAI CHARACTER TO PATAK */ + XK_Thai_thothan = 0x0db0, /* U+0E10 THAI CHARACTER THO THAN */ + XK_Thai_thonangmontho = 0x0db1, /* U+0E11 THAI CHARACTER THO NANGMONTHO */ + XK_Thai_thophuthao = 0x0db2, /* U+0E12 THAI CHARACTER THO PHUTHAO */ + XK_Thai_nonen = 0x0db3, /* U+0E13 THAI CHARACTER NO NEN */ + XK_Thai_dodek = 0x0db4, /* U+0E14 THAI CHARACTER DO DEK */ + XK_Thai_totao = 0x0db5, /* U+0E15 THAI CHARACTER TO TAO */ + XK_Thai_thothung = 0x0db6, /* U+0E16 THAI CHARACTER THO THUNG */ + XK_Thai_thothahan = 0x0db7, /* U+0E17 THAI CHARACTER THO THAHAN */ + XK_Thai_thothong = 0x0db8, /* U+0E18 THAI CHARACTER THO THONG */ + XK_Thai_nonu = 0x0db9, /* U+0E19 THAI CHARACTER NO NU */ + XK_Thai_bobaimai = 0x0dba, /* U+0E1A THAI CHARACTER BO BAIMAI */ + XK_Thai_popla = 0x0dbb, /* U+0E1B THAI CHARACTER PO PLA */ + XK_Thai_phophung = 0x0dbc, /* U+0E1C THAI CHARACTER PHO PHUNG */ + XK_Thai_fofa = 0x0dbd, /* U+0E1D THAI CHARACTER FO FA */ + XK_Thai_phophan = 0x0dbe, /* U+0E1E THAI CHARACTER PHO PHAN */ + XK_Thai_fofan = 0x0dbf, /* U+0E1F THAI CHARACTER FO FAN */ + XK_Thai_phosamphao = 0x0dc0, /* U+0E20 THAI CHARACTER PHO SAMPHAO */ + XK_Thai_moma = 0x0dc1, /* U+0E21 THAI CHARACTER MO MA */ + XK_Thai_yoyak = 0x0dc2, /* U+0E22 THAI CHARACTER YO YAK */ + XK_Thai_rorua = 0x0dc3, /* U+0E23 THAI CHARACTER RO RUA */ + XK_Thai_ru = 0x0dc4, /* U+0E24 THAI CHARACTER RU */ + XK_Thai_loling = 0x0dc5, /* U+0E25 THAI CHARACTER LO LING */ + XK_Thai_lu = 0x0dc6, /* U+0E26 THAI CHARACTER LU */ + XK_Thai_wowaen = 0x0dc7, /* U+0E27 THAI CHARACTER WO WAEN */ + XK_Thai_sosala = 0x0dc8, /* U+0E28 THAI CHARACTER SO SALA */ + XK_Thai_sorusi = 0x0dc9, /* U+0E29 THAI CHARACTER SO RUSI */ + XK_Thai_sosua = 0x0dca, /* U+0E2A THAI CHARACTER SO SUA */ + XK_Thai_hohip = 0x0dcb, /* U+0E2B THAI CHARACTER HO HIP */ + XK_Thai_lochula = 0x0dcc, /* U+0E2C THAI CHARACTER LO CHULA */ + XK_Thai_oang = 0x0dcd, /* U+0E2D THAI CHARACTER O ANG */ + XK_Thai_honokhuk = 0x0dce, /* U+0E2E THAI CHARACTER HO NOKHUK */ + XK_Thai_paiyannoi = 0x0dcf, /* U+0E2F THAI CHARACTER PAIYANNOI */ + XK_Thai_saraa = 0x0dd0, /* U+0E30 THAI CHARACTER SARA A */ + XK_Thai_maihanakat = 0x0dd1, /* U+0E31 THAI CHARACTER MAI HAN-AKAT */ + XK_Thai_saraaa = 0x0dd2, /* U+0E32 THAI CHARACTER SARA AA */ + XK_Thai_saraam = 0x0dd3, /* U+0E33 THAI CHARACTER SARA AM */ + XK_Thai_sarai = 0x0dd4, /* U+0E34 THAI CHARACTER SARA I */ + XK_Thai_saraii = 0x0dd5, /* U+0E35 THAI CHARACTER SARA II */ + XK_Thai_saraue = 0x0dd6, /* U+0E36 THAI CHARACTER SARA UE */ + XK_Thai_sarauee = 0x0dd7, /* U+0E37 THAI CHARACTER SARA UEE */ + XK_Thai_sarau = 0x0dd8, /* U+0E38 THAI CHARACTER SARA U */ + XK_Thai_sarauu = 0x0dd9, /* U+0E39 THAI CHARACTER SARA UU */ + XK_Thai_phinthu = 0x0dda, /* U+0E3A THAI CHARACTER PHINTHU */ + XK_Thai_maihanakat_maitho = 0x0dde, + XK_Thai_baht = 0x0ddf, /* U+0E3F THAI CURRENCY SYMBOL BAHT */ + XK_Thai_sarae = 0x0de0, /* U+0E40 THAI CHARACTER SARA E */ + XK_Thai_saraae = 0x0de1, /* U+0E41 THAI CHARACTER SARA AE */ + XK_Thai_sarao = 0x0de2, /* U+0E42 THAI CHARACTER SARA O */ + XK_Thai_saraaimaimuan = 0x0de3, /* U+0E43 THAI CHARACTER SARA AI MAIMUAN */ + XK_Thai_saraaimaimalai = 0x0de4, /* U+0E44 THAI CHARACTER SARA AI MAIMALAI */ + XK_Thai_lakkhangyao = 0x0de5, /* U+0E45 THAI CHARACTER LAKKHANGYAO */ + XK_Thai_maiyamok = 0x0de6, /* U+0E46 THAI CHARACTER MAIYAMOK */ + XK_Thai_maitaikhu = 0x0de7, /* U+0E47 THAI CHARACTER MAITAIKHU */ + XK_Thai_maiek = 0x0de8, /* U+0E48 THAI CHARACTER MAI EK */ + XK_Thai_maitho = 0x0de9, /* U+0E49 THAI CHARACTER MAI THO */ + XK_Thai_maitri = 0x0dea, /* U+0E4A THAI CHARACTER MAI TRI */ + XK_Thai_maichattawa = 0x0deb, /* U+0E4B THAI CHARACTER MAI CHATTAWA */ + XK_Thai_thanthakhat = 0x0dec, /* U+0E4C THAI CHARACTER THANTHAKHAT */ + XK_Thai_nikhahit = 0x0ded, /* U+0E4D THAI CHARACTER NIKHAHIT */ + XK_Thai_leksun = 0x0df0, /* U+0E50 THAI DIGIT ZERO */ + XK_Thai_leknung = 0x0df1, /* U+0E51 THAI DIGIT ONE */ + XK_Thai_leksong = 0x0df2, /* U+0E52 THAI DIGIT TWO */ + XK_Thai_leksam = 0x0df3, /* U+0E53 THAI DIGIT THREE */ + XK_Thai_leksi = 0x0df4, /* U+0E54 THAI DIGIT FOUR */ + XK_Thai_lekha = 0x0df5, /* U+0E55 THAI DIGIT FIVE */ + XK_Thai_lekhok = 0x0df6, /* U+0E56 THAI DIGIT SIX */ + XK_Thai_lekchet = 0x0df7, /* U+0E57 THAI DIGIT SEVEN */ + XK_Thai_lekpaet = 0x0df8, /* U+0E58 THAI DIGIT EIGHT */ + XK_Thai_lekkao = 0x0df9, /* U+0E59 THAI DIGIT NINE */ + XK_Hangul = 0xff31, /* Hangul start/stop(toggle) */ + XK_Hangul_Start = 0xff32, /* Hangul start */ + XK_Hangul_End = 0xff33, /* Hangul end, English start */ + XK_Hangul_Hanja = 0xff34, /* Start Hangul->Hanja Conversion */ + XK_Hangul_Jamo = 0xff35, /* Hangul Jamo mode */ + XK_Hangul_Romaja = 0xff36, /* Hangul Romaja mode */ + XK_Hangul_Codeinput = 0xff37, /* Hangul code input mode */ + XK_Hangul_Jeonja = 0xff38, /* Jeonja mode */ + XK_Hangul_Banja = 0xff39, /* Banja mode */ + XK_Hangul_PreHanja = 0xff3a, /* Pre Hanja conversion */ + XK_Hangul_PostHanja = 0xff3b, /* Post Hanja conversion */ + XK_Hangul_SingleCandidate = 0xff3c, /* Single candidate */ + XK_Hangul_MultipleCandidate = 0xff3d, /* Multiple candidate */ + XK_Hangul_PreviousCandidate = 0xff3e, /* Previous candidate */ + XK_Hangul_Special = 0xff3f, /* Special symbols */ + XK_Hangul_switch = 0xff7e, /* Alias for mode_switch */ + XK_Hangul_Kiyeog = 0x0ea1, + XK_Hangul_SsangKiyeog = 0x0ea2, + XK_Hangul_KiyeogSios = 0x0ea3, + XK_Hangul_Nieun = 0x0ea4, + XK_Hangul_NieunJieuj = 0x0ea5, + XK_Hangul_NieunHieuh = 0x0ea6, + XK_Hangul_Dikeud = 0x0ea7, + XK_Hangul_SsangDikeud = 0x0ea8, + XK_Hangul_Rieul = 0x0ea9, + XK_Hangul_RieulKiyeog = 0x0eaa, + XK_Hangul_RieulMieum = 0x0eab, + XK_Hangul_RieulPieub = 0x0eac, + XK_Hangul_RieulSios = 0x0ead, + XK_Hangul_RieulTieut = 0x0eae, + XK_Hangul_RieulPhieuf = 0x0eaf, + XK_Hangul_RieulHieuh = 0x0eb0, + XK_Hangul_Mieum = 0x0eb1, + XK_Hangul_Pieub = 0x0eb2, + XK_Hangul_SsangPieub = 0x0eb3, + XK_Hangul_PieubSios = 0x0eb4, + XK_Hangul_Sios = 0x0eb5, + XK_Hangul_SsangSios = 0x0eb6, + XK_Hangul_Ieung = 0x0eb7, + XK_Hangul_Jieuj = 0x0eb8, + XK_Hangul_SsangJieuj = 0x0eb9, + XK_Hangul_Cieuc = 0x0eba, + XK_Hangul_Khieuq = 0x0ebb, + XK_Hangul_Tieut = 0x0ebc, + XK_Hangul_Phieuf = 0x0ebd, + XK_Hangul_Hieuh = 0x0ebe, + XK_Hangul_A = 0x0ebf, + XK_Hangul_AE = 0x0ec0, + XK_Hangul_YA = 0x0ec1, + XK_Hangul_YAE = 0x0ec2, + XK_Hangul_EO = 0x0ec3, + XK_Hangul_E = 0x0ec4, + XK_Hangul_YEO = 0x0ec5, + XK_Hangul_YE = 0x0ec6, + XK_Hangul_O = 0x0ec7, + XK_Hangul_WA = 0x0ec8, + XK_Hangul_WAE = 0x0ec9, + XK_Hangul_OE = 0x0eca, + XK_Hangul_YO = 0x0ecb, + XK_Hangul_U = 0x0ecc, + XK_Hangul_WEO = 0x0ecd, + XK_Hangul_WE = 0x0ece, + XK_Hangul_WI = 0x0ecf, + XK_Hangul_YU = 0x0ed0, + XK_Hangul_EU = 0x0ed1, + XK_Hangul_YI = 0x0ed2, + XK_Hangul_I = 0x0ed3, + XK_Hangul_J_Kiyeog = 0x0ed4, + XK_Hangul_J_SsangKiyeog = 0x0ed5, + XK_Hangul_J_KiyeogSios = 0x0ed6, + XK_Hangul_J_Nieun = 0x0ed7, + XK_Hangul_J_NieunJieuj = 0x0ed8, + XK_Hangul_J_NieunHieuh = 0x0ed9, + XK_Hangul_J_Dikeud = 0x0eda, + XK_Hangul_J_Rieul = 0x0edb, + XK_Hangul_J_RieulKiyeog = 0x0edc, + XK_Hangul_J_RieulMieum = 0x0edd, + XK_Hangul_J_RieulPieub = 0x0ede, + XK_Hangul_J_RieulSios = 0x0edf, + XK_Hangul_J_RieulTieut = 0x0ee0, + XK_Hangul_J_RieulPhieuf = 0x0ee1, + XK_Hangul_J_RieulHieuh = 0x0ee2, + XK_Hangul_J_Mieum = 0x0ee3, + XK_Hangul_J_Pieub = 0x0ee4, + XK_Hangul_J_PieubSios = 0x0ee5, + XK_Hangul_J_Sios = 0x0ee6, + XK_Hangul_J_SsangSios = 0x0ee7, + XK_Hangul_J_Ieung = 0x0ee8, + XK_Hangul_J_Jieuj = 0x0ee9, + XK_Hangul_J_Cieuc = 0x0eea, + XK_Hangul_J_Khieuq = 0x0eeb, + XK_Hangul_J_Tieut = 0x0eec, + XK_Hangul_J_Phieuf = 0x0eed, + XK_Hangul_J_Hieuh = 0x0eee, + XK_Hangul_RieulYeorinHieuh = 0x0eef, + XK_Hangul_SunkyeongeumMieum = 0x0ef0, + XK_Hangul_SunkyeongeumPieub = 0x0ef1, + XK_Hangul_PanSios = 0x0ef2, + XK_Hangul_KkogjiDalrinIeung = 0x0ef3, + XK_Hangul_SunkyeongeumPhieuf = 0x0ef4, + XK_Hangul_YeorinHieuh = 0x0ef5, + XK_Hangul_AraeA = 0x0ef6, + XK_Hangul_AraeAE = 0x0ef7, + XK_Hangul_J_PanSios = 0x0ef8, + XK_Hangul_J_KkogjiDalrinIeung = 0x0ef9, + XK_Hangul_J_YeorinHieuh = 0x0efa, + XK_Korean_Won = 0x0eff, /*(U+20A9 WON SIGN)*/ + XK_Armenian_ligature_ew = 0x1000587, /* U+0587 ARMENIAN SMALL LIGATURE ECH YIWN */ + XK_Armenian_full_stop = 0x1000589, /* U+0589 ARMENIAN FULL STOP */ + XK_Armenian_verjaket = 0x1000589, /* U+0589 ARMENIAN FULL STOP */ + XK_Armenian_separation_mark = 0x100055d, /* U+055D ARMENIAN COMMA */ + XK_Armenian_but = 0x100055d, /* U+055D ARMENIAN COMMA */ + XK_Armenian_hyphen = 0x100058a, /* U+058A ARMENIAN HYPHEN */ + XK_Armenian_yentamna = 0x100058a, /* U+058A ARMENIAN HYPHEN */ + XK_Armenian_exclam = 0x100055c, /* U+055C ARMENIAN EXCLAMATION MARK */ + XK_Armenian_amanak = 0x100055c, /* U+055C ARMENIAN EXCLAMATION MARK */ + XK_Armenian_accent = 0x100055b, /* U+055B ARMENIAN EMPHASIS MARK */ + XK_Armenian_shesht = 0x100055b, /* U+055B ARMENIAN EMPHASIS MARK */ + XK_Armenian_question = 0x100055e, /* U+055E ARMENIAN QUESTION MARK */ + XK_Armenian_paruyk = 0x100055e, /* U+055E ARMENIAN QUESTION MARK */ + XK_Armenian_AYB = 0x1000531, /* U+0531 ARMENIAN CAPITAL LETTER AYB */ + XK_Armenian_ayb = 0x1000561, /* U+0561 ARMENIAN SMALL LETTER AYB */ + XK_Armenian_BEN = 0x1000532, /* U+0532 ARMENIAN CAPITAL LETTER BEN */ + XK_Armenian_ben = 0x1000562, /* U+0562 ARMENIAN SMALL LETTER BEN */ + XK_Armenian_GIM = 0x1000533, /* U+0533 ARMENIAN CAPITAL LETTER GIM */ + XK_Armenian_gim = 0x1000563, /* U+0563 ARMENIAN SMALL LETTER GIM */ + XK_Armenian_DA = 0x1000534, /* U+0534 ARMENIAN CAPITAL LETTER DA */ + XK_Armenian_da = 0x1000564, /* U+0564 ARMENIAN SMALL LETTER DA */ + XK_Armenian_YECH = 0x1000535, /* U+0535 ARMENIAN CAPITAL LETTER ECH */ + XK_Armenian_yech = 0x1000565, /* U+0565 ARMENIAN SMALL LETTER ECH */ + XK_Armenian_ZA = 0x1000536, /* U+0536 ARMENIAN CAPITAL LETTER ZA */ + XK_Armenian_za = 0x1000566, /* U+0566 ARMENIAN SMALL LETTER ZA */ + XK_Armenian_E = 0x1000537, /* U+0537 ARMENIAN CAPITAL LETTER EH */ + XK_Armenian_e = 0x1000567, /* U+0567 ARMENIAN SMALL LETTER EH */ + XK_Armenian_AT = 0x1000538, /* U+0538 ARMENIAN CAPITAL LETTER ET */ + XK_Armenian_at = 0x1000568, /* U+0568 ARMENIAN SMALL LETTER ET */ + XK_Armenian_TO = 0x1000539, /* U+0539 ARMENIAN CAPITAL LETTER TO */ + XK_Armenian_to = 0x1000569, /* U+0569 ARMENIAN SMALL LETTER TO */ + XK_Armenian_ZHE = 0x100053a, /* U+053A ARMENIAN CAPITAL LETTER ZHE */ + XK_Armenian_zhe = 0x100056a, /* U+056A ARMENIAN SMALL LETTER ZHE */ + XK_Armenian_INI = 0x100053b, /* U+053B ARMENIAN CAPITAL LETTER INI */ + XK_Armenian_ini = 0x100056b, /* U+056B ARMENIAN SMALL LETTER INI */ + XK_Armenian_LYUN = 0x100053c, /* U+053C ARMENIAN CAPITAL LETTER LIWN */ + XK_Armenian_lyun = 0x100056c, /* U+056C ARMENIAN SMALL LETTER LIWN */ + XK_Armenian_KHE = 0x100053d, /* U+053D ARMENIAN CAPITAL LETTER XEH */ + XK_Armenian_khe = 0x100056d, /* U+056D ARMENIAN SMALL LETTER XEH */ + XK_Armenian_TSA = 0x100053e, /* U+053E ARMENIAN CAPITAL LETTER CA */ + XK_Armenian_tsa = 0x100056e, /* U+056E ARMENIAN SMALL LETTER CA */ + XK_Armenian_KEN = 0x100053f, /* U+053F ARMENIAN CAPITAL LETTER KEN */ + XK_Armenian_ken = 0x100056f, /* U+056F ARMENIAN SMALL LETTER KEN */ + XK_Armenian_HO = 0x1000540, /* U+0540 ARMENIAN CAPITAL LETTER HO */ + XK_Armenian_ho = 0x1000570, /* U+0570 ARMENIAN SMALL LETTER HO */ + XK_Armenian_DZA = 0x1000541, /* U+0541 ARMENIAN CAPITAL LETTER JA */ + XK_Armenian_dza = 0x1000571, /* U+0571 ARMENIAN SMALL LETTER JA */ + XK_Armenian_GHAT = 0x1000542, /* U+0542 ARMENIAN CAPITAL LETTER GHAD */ + XK_Armenian_ghat = 0x1000572, /* U+0572 ARMENIAN SMALL LETTER GHAD */ + XK_Armenian_TCHE = 0x1000543, /* U+0543 ARMENIAN CAPITAL LETTER CHEH */ + XK_Armenian_tche = 0x1000573, /* U+0573 ARMENIAN SMALL LETTER CHEH */ + XK_Armenian_MEN = 0x1000544, /* U+0544 ARMENIAN CAPITAL LETTER MEN */ + XK_Armenian_men = 0x1000574, /* U+0574 ARMENIAN SMALL LETTER MEN */ + XK_Armenian_HI = 0x1000545, /* U+0545 ARMENIAN CAPITAL LETTER YI */ + XK_Armenian_hi = 0x1000575, /* U+0575 ARMENIAN SMALL LETTER YI */ + XK_Armenian_NU = 0x1000546, /* U+0546 ARMENIAN CAPITAL LETTER NOW */ + XK_Armenian_nu = 0x1000576, /* U+0576 ARMENIAN SMALL LETTER NOW */ + XK_Armenian_SHA = 0x1000547, /* U+0547 ARMENIAN CAPITAL LETTER SHA */ + XK_Armenian_sha = 0x1000577, /* U+0577 ARMENIAN SMALL LETTER SHA */ + XK_Armenian_VO = 0x1000548, /* U+0548 ARMENIAN CAPITAL LETTER VO */ + XK_Armenian_vo = 0x1000578, /* U+0578 ARMENIAN SMALL LETTER VO */ + XK_Armenian_CHA = 0x1000549, /* U+0549 ARMENIAN CAPITAL LETTER CHA */ + XK_Armenian_cha = 0x1000579, /* U+0579 ARMENIAN SMALL LETTER CHA */ + XK_Armenian_PE = 0x100054a, /* U+054A ARMENIAN CAPITAL LETTER PEH */ + XK_Armenian_pe = 0x100057a, /* U+057A ARMENIAN SMALL LETTER PEH */ + XK_Armenian_JE = 0x100054b, /* U+054B ARMENIAN CAPITAL LETTER JHEH */ + XK_Armenian_je = 0x100057b, /* U+057B ARMENIAN SMALL LETTER JHEH */ + XK_Armenian_RA = 0x100054c, /* U+054C ARMENIAN CAPITAL LETTER RA */ + XK_Armenian_ra = 0x100057c, /* U+057C ARMENIAN SMALL LETTER RA */ + XK_Armenian_SE = 0x100054d, /* U+054D ARMENIAN CAPITAL LETTER SEH */ + XK_Armenian_se = 0x100057d, /* U+057D ARMENIAN SMALL LETTER SEH */ + XK_Armenian_VEV = 0x100054e, /* U+054E ARMENIAN CAPITAL LETTER VEW */ + XK_Armenian_vev = 0x100057e, /* U+057E ARMENIAN SMALL LETTER VEW */ + XK_Armenian_TYUN = 0x100054f, /* U+054F ARMENIAN CAPITAL LETTER TIWN */ + XK_Armenian_tyun = 0x100057f, /* U+057F ARMENIAN SMALL LETTER TIWN */ + XK_Armenian_RE = 0x1000550, /* U+0550 ARMENIAN CAPITAL LETTER REH */ + XK_Armenian_re = 0x1000580, /* U+0580 ARMENIAN SMALL LETTER REH */ + XK_Armenian_TSO = 0x1000551, /* U+0551 ARMENIAN CAPITAL LETTER CO */ + XK_Armenian_tso = 0x1000581, /* U+0581 ARMENIAN SMALL LETTER CO */ + XK_Armenian_VYUN = 0x1000552, /* U+0552 ARMENIAN CAPITAL LETTER YIWN */ + XK_Armenian_vyun = 0x1000582, /* U+0582 ARMENIAN SMALL LETTER YIWN */ + XK_Armenian_PYUR = 0x1000553, /* U+0553 ARMENIAN CAPITAL LETTER PIWR */ + XK_Armenian_pyur = 0x1000583, /* U+0583 ARMENIAN SMALL LETTER PIWR */ + XK_Armenian_KE = 0x1000554, /* U+0554 ARMENIAN CAPITAL LETTER KEH */ + XK_Armenian_ke = 0x1000584, /* U+0584 ARMENIAN SMALL LETTER KEH */ + XK_Armenian_O = 0x1000555, /* U+0555 ARMENIAN CAPITAL LETTER OH */ + XK_Armenian_o = 0x1000585, /* U+0585 ARMENIAN SMALL LETTER OH */ + XK_Armenian_FE = 0x1000556, /* U+0556 ARMENIAN CAPITAL LETTER FEH */ + XK_Armenian_fe = 0x1000586, /* U+0586 ARMENIAN SMALL LETTER FEH */ + XK_Armenian_apostrophe = 0x100055a, /* U+055A ARMENIAN APOSTROPHE */ + XK_Georgian_an = 0x10010d0, /* U+10D0 GEORGIAN LETTER AN */ + XK_Georgian_ban = 0x10010d1, /* U+10D1 GEORGIAN LETTER BAN */ + XK_Georgian_gan = 0x10010d2, /* U+10D2 GEORGIAN LETTER GAN */ + XK_Georgian_don = 0x10010d3, /* U+10D3 GEORGIAN LETTER DON */ + XK_Georgian_en = 0x10010d4, /* U+10D4 GEORGIAN LETTER EN */ + XK_Georgian_vin = 0x10010d5, /* U+10D5 GEORGIAN LETTER VIN */ + XK_Georgian_zen = 0x10010d6, /* U+10D6 GEORGIAN LETTER ZEN */ + XK_Georgian_tan = 0x10010d7, /* U+10D7 GEORGIAN LETTER TAN */ + XK_Georgian_in = 0x10010d8, /* U+10D8 GEORGIAN LETTER IN */ + XK_Georgian_kan = 0x10010d9, /* U+10D9 GEORGIAN LETTER KAN */ + XK_Georgian_las = 0x10010da, /* U+10DA GEORGIAN LETTER LAS */ + XK_Georgian_man = 0x10010db, /* U+10DB GEORGIAN LETTER MAN */ + XK_Georgian_nar = 0x10010dc, /* U+10DC GEORGIAN LETTER NAR */ + XK_Georgian_on = 0x10010dd, /* U+10DD GEORGIAN LETTER ON */ + XK_Georgian_par = 0x10010de, /* U+10DE GEORGIAN LETTER PAR */ + XK_Georgian_zhar = 0x10010df, /* U+10DF GEORGIAN LETTER ZHAR */ + XK_Georgian_rae = 0x10010e0, /* U+10E0 GEORGIAN LETTER RAE */ + XK_Georgian_san = 0x10010e1, /* U+10E1 GEORGIAN LETTER SAN */ + XK_Georgian_tar = 0x10010e2, /* U+10E2 GEORGIAN LETTER TAR */ + XK_Georgian_un = 0x10010e3, /* U+10E3 GEORGIAN LETTER UN */ + XK_Georgian_phar = 0x10010e4, /* U+10E4 GEORGIAN LETTER PHAR */ + XK_Georgian_khar = 0x10010e5, /* U+10E5 GEORGIAN LETTER KHAR */ + XK_Georgian_ghan = 0x10010e6, /* U+10E6 GEORGIAN LETTER GHAN */ + XK_Georgian_qar = 0x10010e7, /* U+10E7 GEORGIAN LETTER QAR */ + XK_Georgian_shin = 0x10010e8, /* U+10E8 GEORGIAN LETTER SHIN */ + XK_Georgian_chin = 0x10010e9, /* U+10E9 GEORGIAN LETTER CHIN */ + XK_Georgian_can = 0x10010ea, /* U+10EA GEORGIAN LETTER CAN */ + XK_Georgian_jil = 0x10010eb, /* U+10EB GEORGIAN LETTER JIL */ + XK_Georgian_cil = 0x10010ec, /* U+10EC GEORGIAN LETTER CIL */ + XK_Georgian_char = 0x10010ed, /* U+10ED GEORGIAN LETTER CHAR */ + XK_Georgian_xan = 0x10010ee, /* U+10EE GEORGIAN LETTER XAN */ + XK_Georgian_jhan = 0x10010ef, /* U+10EF GEORGIAN LETTER JHAN */ + XK_Georgian_hae = 0x10010f0, /* U+10F0 GEORGIAN LETTER HAE */ + XK_Georgian_he = 0x10010f1, /* U+10F1 GEORGIAN LETTER HE */ + XK_Georgian_hie = 0x10010f2, /* U+10F2 GEORGIAN LETTER HIE */ + XK_Georgian_we = 0x10010f3, /* U+10F3 GEORGIAN LETTER WE */ + XK_Georgian_har = 0x10010f4, /* U+10F4 GEORGIAN LETTER HAR */ + XK_Georgian_hoe = 0x10010f5, /* U+10F5 GEORGIAN LETTER HOE */ + XK_Georgian_fi = 0x10010f6, /* U+10F6 GEORGIAN LETTER FI */ + XK_Xabovedot = 0x1001e8a, /* U+1E8A LATIN CAPITAL LETTER X WITH DOT ABOVE */ + XK_Ibreve = 0x100012c, /* U+012C LATIN CAPITAL LETTER I WITH BREVE */ + XK_Zstroke = 0x10001b5, /* U+01B5 LATIN CAPITAL LETTER Z WITH STROKE */ + XK_Gcaron = 0x10001e6, /* U+01E6 LATIN CAPITAL LETTER G WITH CARON */ + XK_Ocaron = 0x10001d1, /* U+01D2 LATIN CAPITAL LETTER O WITH CARON */ + XK_Obarred = 0x100019f, /* U+019F LATIN CAPITAL LETTER O WITH MIDDLE TILDE */ + XK_xabovedot = 0x1001e8b, /* U+1E8B LATIN SMALL LETTER X WITH DOT ABOVE */ + XK_ibreve = 0x100012d, /* U+012D LATIN SMALL LETTER I WITH BREVE */ + XK_zstroke = 0x10001b6, /* U+01B6 LATIN SMALL LETTER Z WITH STROKE */ + XK_gcaron = 0x10001e7, /* U+01E7 LATIN SMALL LETTER G WITH CARON */ + XK_ocaron = 0x10001d2, /* U+01D2 LATIN SMALL LETTER O WITH CARON */ + XK_obarred = 0x1000275, /* U+0275 LATIN SMALL LETTER BARRED O */ + XK_SCHWA = 0x100018f, /* U+018F LATIN CAPITAL LETTER SCHWA */ + XK_schwa = 0x1000259, /* U+0259 LATIN SMALL LETTER SCHWA */ + XK_Lbelowdot = 0x1001e36, /* U+1E36 LATIN CAPITAL LETTER L WITH DOT BELOW */ + XK_lbelowdot = 0x1001e37, /* U+1E37 LATIN SMALL LETTER L WITH DOT BELOW */ + XK_Abelowdot = 0x1001ea0, /* U+1EA0 LATIN CAPITAL LETTER A WITH DOT BELOW */ + XK_abelowdot = 0x1001ea1, /* U+1EA1 LATIN SMALL LETTER A WITH DOT BELOW */ + XK_Ahook = 0x1001ea2, /* U+1EA2 LATIN CAPITAL LETTER A WITH HOOK ABOVE */ + XK_ahook = 0x1001ea3, /* U+1EA3 LATIN SMALL LETTER A WITH HOOK ABOVE */ + XK_Acircumflexacute = 0x1001ea4, /* U+1EA4 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */ + XK_acircumflexacute = 0x1001ea5, /* U+1EA5 LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE */ + XK_Acircumflexgrave = 0x1001ea6, /* U+1EA6 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */ + XK_acircumflexgrave = 0x1001ea7, /* U+1EA7 LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE */ + XK_Acircumflexhook = 0x1001ea8, /* U+1EA8 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */ + XK_acircumflexhook = 0x1001ea9, /* U+1EA9 LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */ + XK_Acircumflextilde = 0x1001eaa, /* U+1EAA LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */ + XK_acircumflextilde = 0x1001eab, /* U+1EAB LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE */ + XK_Acircumflexbelowdot = 0x1001eac, /* U+1EAC LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */ + XK_acircumflexbelowdot = 0x1001ead, /* U+1EAD LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW */ + XK_Abreveacute = 0x1001eae, /* U+1EAE LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */ + XK_abreveacute = 0x1001eaf, /* U+1EAF LATIN SMALL LETTER A WITH BREVE AND ACUTE */ + XK_Abrevegrave = 0x1001eb0, /* U+1EB0 LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */ + XK_abrevegrave = 0x1001eb1, /* U+1EB1 LATIN SMALL LETTER A WITH BREVE AND GRAVE */ + XK_Abrevehook = 0x1001eb2, /* U+1EB2 LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */ + XK_abrevehook = 0x1001eb3, /* U+1EB3 LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE */ + XK_Abrevetilde = 0x1001eb4, /* U+1EB4 LATIN CAPITAL LETTER A WITH BREVE AND TILDE */ + XK_abrevetilde = 0x1001eb5, /* U+1EB5 LATIN SMALL LETTER A WITH BREVE AND TILDE */ + XK_Abrevebelowdot = 0x1001eb6, /* U+1EB6 LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */ + XK_abrevebelowdot = 0x1001eb7, /* U+1EB7 LATIN SMALL LETTER A WITH BREVE AND DOT BELOW */ + XK_Ebelowdot = 0x1001eb8, /* U+1EB8 LATIN CAPITAL LETTER E WITH DOT BELOW */ + XK_ebelowdot = 0x1001eb9, /* U+1EB9 LATIN SMALL LETTER E WITH DOT BELOW */ + XK_Ehook = 0x1001eba, /* U+1EBA LATIN CAPITAL LETTER E WITH HOOK ABOVE */ + XK_ehook = 0x1001ebb, /* U+1EBB LATIN SMALL LETTER E WITH HOOK ABOVE */ + XK_Etilde = 0x1001ebc, /* U+1EBC LATIN CAPITAL LETTER E WITH TILDE */ + XK_etilde = 0x1001ebd, /* U+1EBD LATIN SMALL LETTER E WITH TILDE */ + XK_Ecircumflexacute = 0x1001ebe, /* U+1EBE LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */ + XK_ecircumflexacute = 0x1001ebf, /* U+1EBF LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE */ + XK_Ecircumflexgrave = 0x1001ec0, /* U+1EC0 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */ + XK_ecircumflexgrave = 0x1001ec1, /* U+1EC1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE */ + XK_Ecircumflexhook = 0x1001ec2, /* U+1EC2 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */ + XK_ecircumflexhook = 0x1001ec3, /* U+1EC3 LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */ + XK_Ecircumflextilde = 0x1001ec4, /* U+1EC4 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */ + XK_ecircumflextilde = 0x1001ec5, /* U+1EC5 LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE */ + XK_Ecircumflexbelowdot = 0x1001ec6, /* U+1EC6 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */ + XK_ecircumflexbelowdot = 0x1001ec7, /* U+1EC7 LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW */ + XK_Ihook = 0x1001ec8, /* U+1EC8 LATIN CAPITAL LETTER I WITH HOOK ABOVE */ + XK_ihook = 0x1001ec9, /* U+1EC9 LATIN SMALL LETTER I WITH HOOK ABOVE */ + XK_Ibelowdot = 0x1001eca, /* U+1ECA LATIN CAPITAL LETTER I WITH DOT BELOW */ + XK_ibelowdot = 0x1001ecb, /* U+1ECB LATIN SMALL LETTER I WITH DOT BELOW */ + XK_Obelowdot = 0x1001ecc, /* U+1ECC LATIN CAPITAL LETTER O WITH DOT BELOW */ + XK_obelowdot = 0x1001ecd, /* U+1ECD LATIN SMALL LETTER O WITH DOT BELOW */ + XK_Ohook = 0x1001ece, /* U+1ECE LATIN CAPITAL LETTER O WITH HOOK ABOVE */ + XK_ohook = 0x1001ecf, /* U+1ECF LATIN SMALL LETTER O WITH HOOK ABOVE */ + XK_Ocircumflexacute = 0x1001ed0, /* U+1ED0 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */ + XK_ocircumflexacute = 0x1001ed1, /* U+1ED1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE */ + XK_Ocircumflexgrave = 0x1001ed2, /* U+1ED2 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */ + XK_ocircumflexgrave = 0x1001ed3, /* U+1ED3 LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE */ + XK_Ocircumflexhook = 0x1001ed4, /* U+1ED4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */ + XK_ocircumflexhook = 0x1001ed5, /* U+1ED5 LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */ + XK_Ocircumflextilde = 0x1001ed6, /* U+1ED6 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */ + XK_ocircumflextilde = 0x1001ed7, /* U+1ED7 LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE */ + XK_Ocircumflexbelowdot = 0x1001ed8, /* U+1ED8 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */ + XK_ocircumflexbelowdot = 0x1001ed9, /* U+1ED9 LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW */ + XK_Ohornacute = 0x1001eda, /* U+1EDA LATIN CAPITAL LETTER O WITH HORN AND ACUTE */ + XK_ohornacute = 0x1001edb, /* U+1EDB LATIN SMALL LETTER O WITH HORN AND ACUTE */ + XK_Ohorngrave = 0x1001edc, /* U+1EDC LATIN CAPITAL LETTER O WITH HORN AND GRAVE */ + XK_ohorngrave = 0x1001edd, /* U+1EDD LATIN SMALL LETTER O WITH HORN AND GRAVE */ + XK_Ohornhook = 0x1001ede, /* U+1EDE LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */ + XK_ohornhook = 0x1001edf, /* U+1EDF LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE */ + XK_Ohorntilde = 0x1001ee0, /* U+1EE0 LATIN CAPITAL LETTER O WITH HORN AND TILDE */ + XK_ohorntilde = 0x1001ee1, /* U+1EE1 LATIN SMALL LETTER O WITH HORN AND TILDE */ + XK_Ohornbelowdot = 0x1001ee2, /* U+1EE2 LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */ + XK_ohornbelowdot = 0x1001ee3, /* U+1EE3 LATIN SMALL LETTER O WITH HORN AND DOT BELOW */ + XK_Ubelowdot = 0x1001ee4, /* U+1EE4 LATIN CAPITAL LETTER U WITH DOT BELOW */ + XK_ubelowdot = 0x1001ee5, /* U+1EE5 LATIN SMALL LETTER U WITH DOT BELOW */ + XK_Uhook = 0x1001ee6, /* U+1EE6 LATIN CAPITAL LETTER U WITH HOOK ABOVE */ + XK_uhook = 0x1001ee7, /* U+1EE7 LATIN SMALL LETTER U WITH HOOK ABOVE */ + XK_Uhornacute = 0x1001ee8, /* U+1EE8 LATIN CAPITAL LETTER U WITH HORN AND ACUTE */ + XK_uhornacute = 0x1001ee9, /* U+1EE9 LATIN SMALL LETTER U WITH HORN AND ACUTE */ + XK_Uhorngrave = 0x1001eea, /* U+1EEA LATIN CAPITAL LETTER U WITH HORN AND GRAVE */ + XK_uhorngrave = 0x1001eeb, /* U+1EEB LATIN SMALL LETTER U WITH HORN AND GRAVE */ + XK_Uhornhook = 0x1001eec, /* U+1EEC LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */ + XK_uhornhook = 0x1001eed, /* U+1EED LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE */ + XK_Uhorntilde = 0x1001eee, /* U+1EEE LATIN CAPITAL LETTER U WITH HORN AND TILDE */ + XK_uhorntilde = 0x1001eef, /* U+1EEF LATIN SMALL LETTER U WITH HORN AND TILDE */ + XK_Uhornbelowdot = 0x1001ef0, /* U+1EF0 LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */ + XK_uhornbelowdot = 0x1001ef1, /* U+1EF1 LATIN SMALL LETTER U WITH HORN AND DOT BELOW */ + XK_Ybelowdot = 0x1001ef4, /* U+1EF4 LATIN CAPITAL LETTER Y WITH DOT BELOW */ + XK_ybelowdot = 0x1001ef5, /* U+1EF5 LATIN SMALL LETTER Y WITH DOT BELOW */ + XK_Yhook = 0x1001ef6, /* U+1EF6 LATIN CAPITAL LETTER Y WITH HOOK ABOVE */ + XK_yhook = 0x1001ef7, /* U+1EF7 LATIN SMALL LETTER Y WITH HOOK ABOVE */ + XK_Ytilde = 0x1001ef8, /* U+1EF8 LATIN CAPITAL LETTER Y WITH TILDE */ + XK_ytilde = 0x1001ef9, /* U+1EF9 LATIN SMALL LETTER Y WITH TILDE */ + XK_Ohorn = 0x10001a0, /* U+01A0 LATIN CAPITAL LETTER O WITH HORN */ + XK_ohorn = 0x10001a1, /* U+01A1 LATIN SMALL LETTER O WITH HORN */ + XK_Uhorn = 0x10001af, /* U+01AF LATIN CAPITAL LETTER U WITH HORN */ + XK_uhorn = 0x10001b0, /* U+01B0 LATIN SMALL LETTER U WITH HORN */ + XK_EcuSign = 0x10020a0, /* U+20A0 EURO-CURRENCY SIGN */ + XK_ColonSign = 0x10020a1, /* U+20A1 COLON SIGN */ + XK_CruzeiroSign = 0x10020a2, /* U+20A2 CRUZEIRO SIGN */ + XK_FFrancSign = 0x10020a3, /* U+20A3 FRENCH FRANC SIGN */ + XK_LiraSign = 0x10020a4, /* U+20A4 LIRA SIGN */ + XK_MillSign = 0x10020a5, /* U+20A5 MILL SIGN */ + XK_NairaSign = 0x10020a6, /* U+20A6 NAIRA SIGN */ + XK_PesetaSign = 0x10020a7, /* U+20A7 PESETA SIGN */ + XK_RupeeSign = 0x10020a8, /* U+20A8 RUPEE SIGN */ + XK_WonSign = 0x10020a9, /* U+20A9 WON SIGN */ + XK_NewSheqelSign = 0x10020aa, /* U+20AA NEW SHEQEL SIGN */ + XK_DongSign = 0x10020ab, /* U+20AB DONG SIGN */ + XK_EuroSign = 0x20ac, /* U+20AC EURO SIGN */ +} + diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin new file mode 100644 index 000000000..811ed31ee --- /dev/null +++ b/vendor/x11/xlib/xlib_procs.odin @@ -0,0 +1,1549 @@ +//+build linux, openbsd, freebsd +package xlib + +foreign import xlib "system:x11" +foreign xlib { + @(link_name="_Xdebug") _Xdebug: i32 +} + +/* ---- X11/Xlib.h ---------------------------------------------------------*/ + +@(default_calling_convention="c") +foreign xlib { + // Free data allocated by Xlib + XFree :: proc(ptr: rawptr) --- + // Opening/closing a display + XOpenDisplay :: proc(display: ^Display, name: cstring) -> ^Display --- + XCloseDisplay :: proc(display: ^Display) --- + XSetCloseDownMode :: proc(display: ^Display, mode: CloseMode) --- + // Generate a no-op request + XNoOp :: proc(display: ^Display) --- + // Display macros (connection) + XConnectionNumber :: proc(display: ^Display) -> i32 --- + XExtendedMaxRequestSize :: + proc(display: ^Display) -> int --- + XMaxRequestSize :: proc(display: ^Display) -> int --- + XLastKnownRequestProcessed :: + proc(display: ^Display) -> uint --- + XNextRequest :: proc(display: ^Display) -> uint --- + XProtocolVersion :: proc(display: ^Display) -> i32 --- + XProtocolRevision :: proc(display: ^Display) -> i32 --- + XQLength :: proc(display: ^Display) -> i32 --- + XServerVendor :: proc(display: ^Display) -> cstring --- + XVendorRelease :: proc(display: ^Display) -> i32 --- + // Display macros (display properties) + XBlackPixel :: proc(display: ^Display, screen_no: i32) -> uint --- + XWhitePixel :: proc(display: ^Display, screen_no: i32) -> uint --- + XListDepths :: proc(display: ^Display, screen_no: i32, count: ^i32) -> [^]i32 --- + XDisplayCells :: proc(display: ^Display, screen_no: i32) -> i32 --- + XDisplayPlanes :: proc(display: ^Display, screen_no: i32) -> i32 --- + XScreenOfDisplay :: proc(display: ^Display, screen_no: i32) -> ^Screen --- + XDisplayString :: proc(display: ^Display) -> cstring --- + // Display macros (defaults) + XDefaultColormap :: proc(display: ^Display, screen_no: i32) -> Colormap --- + XDefaultDepth :: proc(display: ^Display) -> i32 --- + XDefaultGC :: proc(display: ^Display, screen_no: i32) -> GC --- + XDefaultRootWindow :: proc(display: ^Display) -> Window --- + XDefaultScreen :: proc(display: ^Display) -> ^Screen --- + XDefaultVisual :: proc(display: ^Display, screen_no: i32) -> ^Visual --- + XDefaultScreenOfDisplay :: + proc(display: ^Display) -> ^Screen --- + // Display macros (other) + XRootWindow :: proc(display: ^Display, screen_no: i32) -> Window --- + XScreenCount :: proc(display: ^Display) -> i32 --- + // Display image format macros + XListPixmapFormats :: proc(display: ^Display, count: ^i32) -> [^]XPixmapFormatValues --- + XImageByteOrder :: proc(display: ^Display) -> ByteOrder --- + XBitmapUnit :: proc(display: ^Display) -> i32 --- + XBitmapBitOrder :: proc(display: ^Display) -> ByteOrder --- + XBitmapPad :: proc(display: ^Display) -> i32 --- + XDisplayHeight :: proc(display: ^Display, screen_no: i32) -> i32 --- + XDisplayHeightMM :: proc(display: ^Display, screen_no: i32) -> i32 --- + XDisplayWidth :: proc(display: ^Display, screen_no: i32) -> i32 --- + XDisplayWidthMM :: proc(display: ^Display, screen_no: i32) -> i32 --- + // Screen macros + XBlackPixelsOfScreen :: proc(screen: ^Screen) -> uint --- + XWhitePixelsOfScreen :: proc(screen: ^Screen) -> uint --- + XCellsOfScreen :: proc(screen: ^Screen) -> i32 --- + XDefaultColormapOfScreen :: proc(screen: ^Screen) -> Colormap --- + XDefaultDepthOfScreen :: proc(screen: ^Screen) -> i32 --- + XDefaultGCOfScreen :: proc(screen: ^Screen) -> GC --- + XDefaultVisualOfScreen :: proc(screen: ^Screen) -> ^Visual --- + XDoesBackingStore :: proc(screen: ^Screen) -> BackingStore --- + XDoesSaveUnders :: proc(screen: ^Screen) -> b32 --- + XDisplayOfScreen :: proc(screen: ^Screen) -> ^Display --- + XScreenNumberOfScreens :: proc(screen: ^Screen) -> i32 --- + XEventMaskOfScreen :: proc(screen: ^Screen) -> EventMask --- + XWidthOfScreen :: proc(screen: ^Screen) -> i32 --- + XHeightOfScreen :: proc(screen: ^Screen) -> i32 --- + XWidthMMOfScreen :: proc(screen: ^Screen) -> i32 --- + XHeightMMOfScreen :: proc(screen: ^Screen) -> i32 --- + XMaxCmapsOfScreen :: proc(screen: ^Screen) -> i32 --- + XMinCmapsOfScreen :: proc(screen: ^Screen) -> i32 --- + XPlanesOfScreen :: proc(screen: ^Screen) -> i32 --- + XRootWindowOfScreen :: proc(screen: ^Screen) -> Window --- + // Threading functions + XInitThreads :: proc() -> Status --- + XLockDisplay :: proc(display: ^Display) --- + XUnlockDisplay :: proc(display: ^Display) --- + // Internal connections + XAddConnectionWatch :: proc( + display: ^Display, + procedure: XConnectionWatchProc, + data: rawptr + ) -> Status --- + XRemoveConnectionWatch :: proc( + display: ^Display, + procedure: XConnectionWatchProc, + data: rawptr + ) -> Status --- + XProcessInternalConnections :: proc( + display: ^Display, + fd: i32 + ) --- + XInternalConnectionNumbers :: proc( + display: ^Display, + fds: ^[^]i32, + count: ^i32 + ) -> Status --- + // Windows functions + XVisualIDFromVisual :: proc(visual: ^Visual) -> VisualID --- + // Windows: creation/destruction + XCreateWindow :: proc( + display: ^Display, + parent: Window, + x: i32, + y: i32, + width: u32, + height: u32, + bordersz: u32, + depth: i32, + class: WindowClass, + visual: ^Visual, + attr_mask: WindowAttributeMask, + attr: ^XSetWindowAttributes + ) -> Window --- + XCreateSimpleWindow :: proc( + display: ^Display, + parent: Window, + x: i32, + y: i32, + width: u32, + height: u32, + bordersz: u32, + border: int, + bg: int + ) -> Window --- + XDestroyWindow :: proc(display: ^Display, window: Window) --- + XDestroySubwindows :: proc(display: ^Display, window: Window) --- + // Windows: mapping/unmapping + XMapWindow :: proc(display: ^Display, window: Window) --- + XMapRaised :: proc(display: ^Display, window: Window) --- + XMapSubwindows :: proc(display: ^Display, window: Window) --- + XUnmapWindow :: proc(display: ^Display, window: Window) --- + XUnmapSubwindows :: proc(display: ^Display, window: Window) --- + // Windows: configuring + XConfigureWindow :: proc( + display: ^Display, + window: Window, + mask: WindowChangesMask, + values: XWindowChanges + ) --- + XMoveWindow :: proc( + display: ^Display, + window: Window, + x: i32, + y: i32 + ) --- + XResizeWindow :: proc( + display: ^Display, + window: Window, + width: u32, + height: u32 + ) --- + XMoveResizeWindow :: proc( + display: ^Display, + window: Window, + x: i32, + y: i32, + width: u32, + height: u32 + ) --- + XSetWindowBorderWidth :: proc( + display: ^Display, + window: Window, + width: u32 + ) --- + // Window: changing stacking order + XRaiseWindow :: proc(display: ^Display, window: Window) --- + XLowerWindow :: proc(display: ^Display, window: Window) --- + XCirculateSubwindows :: proc(display: ^Display, window: Window, direction: CirculationDirection) --- + XCirculateSubwindowsUp :: proc(display: ^Display, window: Window) --- + XCirculateSubwindowsDown :: proc(display: ^Display, window: Window) --- + XRestackWindows :: proc(display: ^Display, windows: [^]Window, nwindows: i32) --- + // Window: changing attributes + XChangeWindowAttributes :: proc( + display: ^Display, + window: Window, + attr_mask: WindowAttributeMask, + attr: XWindowAttributes + ) --- + XSetWindowBackground :: proc( + display: ^Display, + window: Window, + pixel: uint + ) --- + XSetWindowBackgroundMap :: proc( + display: ^Display, + window: Window, + pixmap: Pixmap + ) --- + XSetWindowColormap :: proc( + display: ^Display, + window: Window, + colormap: Colormap + ) --- + XDefineCursor :: proc( + display: ^Display, + window: Window, + cursor: Cursor + ) --- + XUndefineCursor :: proc( + display: ^Display, + window: Window + ) --- + // Windows: querying information + XQueryTree :: proc( + display: ^Display, + window: Window, + root: ^Window, + parent: ^Window, + children: ^[^]Window, + nchildren: ^u32 + ) -> Status --- + XGetWindowAttributes :: proc( + display: ^Display, + window: Window, + attr: XWindowAttributes + ) --- + XGetGeometry :: proc( + display: ^Display, + drawable: Drawable, + root: ^Window, + x: ^i32, + y: ^i32, + width: ^u32, + height: ^u32, + border_sz: ^u32, + depth: ^u32 + ) -> Status --- + // Windows: translating screen coordinates + XTranslateCoordinates :: proc( + display: ^Display, + src_window: Window, + dst_window: Window, + src_x: i32, + src_y: i32, + dst_x: ^i32, + dst_y: ^i32 + ) -> b32 --- + XQueryPointer :: proc( + display: ^Display, + window: Window, + root: ^Window, + root_x: ^i32, + root_y: ^i32, + x: ^i32, + y: ^i32, + mask: ^KeyMask + ) -> b32 --- + // Atoms + XInternAtom :: proc( + display: ^Display, + name: cstring, + existing: b32 + ) -> Atom --- + XInternAtoms :: proc( + display: ^Display, + names: [^]cstring, + count: i32, + atoms: [^]Atom + ) -> Status --- + XGetAtomName :: proc( + display: ^Display, + atom: Atom + ) -> cstring --- + XGetAtomNames :: proc( + display: ^Display, + atoms: [^]Atom, + count: i32, + names: [^]cstring + ) -> Status --- + // Windows: Obtaining and changing properties + XGetWindowProperty :: proc( + display: ^Display, + window: Window, + property: Atom, + long_offs: int, + long_len: int, + delete: b32, + req_type: Atom, + act_type: [^]Atom, + act_format: [^]i32, + nitems: [^]uint, + bytes_after: [^]uint, + props: ^rawptr + ) -> i32 --- + XListProperties :: proc( + display: ^Display, + window: Window, + num: ^i32 + ) -> [^]Atom --- + XChangeProperty :: proc( + display: ^Display, + window: Window, + property: Atom, + type: Atom, + format: i32, + mode: i32, + data: rawptr, + count: i32 + ) --- + XRotateWindowProperties :: proc( + display: ^Display, + window: Window, + props: [^]Atom, + nprops: i32, + npos: i32 + ) --- + XDeleteProperty :: proc( + display: ^Display, + window: Window, + prop: Atom + ) --- + // Selections + XSetSelectionOwner :: proc( + display: ^Display, + selection: Atom, + owber: Window, + time: Time + ) --- + XGetSelectionOwner :: proc( + display: ^Display, + selection: Atom + ) -> Window --- + XConvertSelection :: proc( + display: ^Display, + selection: Atom, + target: Atom, + property: Atom, + requestor: Window, + time: Time + ) --- + // Creating and freeing pixmaps + XCreatePixmap :: proc( + display: ^Display, + drawable: Drawable, + width: u32, + height: u32, + depth: u32 + ) -> Pixmap --- + XFreePixmap :: proc( + display: ^Display, + pixmap: Pixmap + ) --- + // Creating recoloring and freeing cursors + XCreateFontCursor :: proc( + display: ^Display, + shape: CursorShape + ) -> Cursor --- + XCreateGlyphCursor :: proc( + display: ^Display, + src_font: Font, + mask_font: Font, + src_char: u32, + mask_char: u32, + fg: ^XColor, + bg: ^XColor + ) -> Cursor --- + XCreatePixmapCursor :: proc( + display: ^Display, + source: Pixmap, + mask: Pixmap, + fg: XColor, + bg: ^XColor, + x: u32, + y: u32 + ) -> Cursor --- + XQueryBestCursor :: proc( + display: ^Display, + drawable: Drawable, + width: u32, + height: u32, + out_width: ^u32, + out_height: ^u32 + ) -> Status --- + XRecolorCursor :: proc( + display: ^Display, + cursor: Cursor, + fg: ^XColor, + bg: ^XColor + ) --- + XFreeCursor :: proc(display: ^Display, cursor: Cursor) --- + // Creation/destruction of colormaps + XCreateColormap :: proc( + display: ^Display, + window: Window, + visual: Visual, + alloc: ColormapAlloc + ) -> Colormap --- + XCopyColormapAndFree :: proc( + display: ^Display, + colormap: Colormap + ) -> Colormap --- + XFreeColormap :: proc( + display: ^Display, + colormap: Colormap + ) --- + // Mapping color names to values + XLookupColor :: proc( + display: ^Display, + colomap: Colormap, + name: cstring, + exact: ^XColor, + screen: ^XColor + ) -> Status --- + XcmsLookupColor :: proc( + display: ^Display, + colormap: Colormap, + name: cstring, + exact: XcmsColor, + screen: XcmsColor, + format: XcmsColorFormat + ) -> Status --- + // Allocating and freeing color cells + XAllocColor :: proc( + display: ^Display, + colormap: Colormap, + screen: ^XColor + ) -> Status --- + XcmsAllocColor :: proc( + display: ^Display, + colormap: Colormap, + color: ^XcmsColor, + format: XcmsColorFormat + ) -> Status --- + XAllocNamedColor :: proc( + display: ^Display, + colormap: Colormap, + name: cstring, + screen: ^XColor, + exact: ^XColor + ) -> Status --- + XcmsAllocNamedColor :: proc( + display: ^Display, + colormap: Colormap, + name: cstring, + screen: ^XcmsColor, + exact: ^XcmsColor, + format: XcmsColorFormat + ) -> Status --- + XAllocColorCells :: proc( + display: ^Display, + colormap: Colormap, + contig: b32, + pmasks: [^]uint, + np: u32, + pixels: [^]uint, + npixels: u32 + ) -> Status --- + XAllocColorPlanes :: proc( + display: ^Display, + colormap: Colormap, + contig: b32, + pixels: [^]uint, + ncolors: i32, + nreds: i32, + ngreens: i32, + nblues: i32, + rmask: [^]uint, + gmask: [^]uint, + bmask: [^]uint + ) -> Status --- + XFreeColors :: proc( + display: ^Display, + colormap: Colormap, + pixels: [^]uint, + npixels: i32, + planes: uint + ) --- + // Modifying and querying colormap cells + XStoreColor :: proc( + display: ^Display, + colormap: Colormap, + color: ^XColor + ) --- + XStoreColors :: proc( + display: ^Display, + colormap: Colormap, + color: [^]XColor, + ncolors: i32 + ) --- + XcmsStoreColor :: proc( + display: ^Display, + colormap: Colormap, + color: ^XcmsColor + ) -> Status --- + XcmsStoreColors :: proc( + display: ^Display, + colormap: Colormap, + colors: [^]XcmsColor, + ncolors: XcmsColor, + cflags: [^]b32 + ) -> Status --- + XStoreNamedColor :: proc( + display: ^Display, + colormap: Colormap, + name: cstring, + pixel: uint, + flags: ColorFlags + ) --- + XQueryColor :: proc( + display: ^Display, + colormap: Colormap, + color: ^XColor + ) --- + XQueryColors :: proc( + display: ^Display, + colormap: Colormap, + colors: [^]XColor, + ncolors: i32 + ) --- + XcmsQueryColor :: proc( + display: ^Display, + colormap: Colormap, + color: ^XcmsColor, + format: XcmsColorFormat + ) -> Status --- + XcmsQueryColors :: proc( + display: ^Display, + colormap: Colormap, + color: [^]XcmsColor, + ncolors: i32, + format: XcmsColorFormat + ) -> Status --- + // Getting and setting the color conversion context (CCC) of a colormap + XcmsCCCOfColormap :: proc( + display: ^Display, + colormap: Colormap + ) -> XcmsCCC --- + XcmsSetCCCOfColormap :: proc( + display: ^Display, + colormap: Colormap, + ccc: XcmsCCC) -> XcmsCCC --- + XcmsDefaultCCC :: proc(display: ^Display, screen_no: i32) -> XcmsCCC --- + // Color conversion context macros + XcmsDisplayOfCCC :: proc(ccc: XcmsCCC) -> ^Display --- + XcmsVisualOfCCC :: proc(ccc: XcmsCCC) -> ^Visual --- + XcmsScreenNumberOfCCC :: + proc(ccc: XcmsCCC) -> i32 --- + XcmsScreenWhitePointOfCCC :: + proc(ccc: XcmsCCC) -> XcmsColor --- + XcmsClientWhitePointOfCCC :: + proc(ccc: XcmsCCC) -> XcmsColor --- + // Modifying the attributes of color conversion context + XcmsSetWhitePoint :: proc( + ccc: XcmsCCC, + color: ^XcmsColor + ) -> Status --- + XcmsSetCompressionProc :: proc( + ccc: XcmsCCC, + cproc: XcmsCompressionProc, + data: rawptr + ) -> XcmsCompressionProc --- + XcmsSetWhiteAdjustProc :: proc( + ccc: XcmsCCC, + aproc: XcmsWhiteAdjustProc, + data: rawptr + ) -> XcmsWhiteAdjustProc --- + // Creating and freeing the color conversion context + XcmsCreateCCC :: proc( + display: ^Display, + screen_no: i32, + visual: ^Visual, + white_point: ^XcmsColor, + cproc: XcmsCompressionProc, + cdata: rawptr, + aproc: XcmsWhiteAdjustProc, + adata: rawptr + ) -> XcmsCCC --- + XcmsFreeCCC :: proc(ccc: XcmsCCC) --- + // Converting between colorspaces + XcmsConvertColors :: proc( + ccc: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + format: XcmsColorFormat, + cflags: [^]b32 + ) -> Status --- + // Pre-defined gamut compression callbacks + XcmsCIELabClipL :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsCIELabClipab :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsCIELabClipLab :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsCIELuvClipL :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsCIELuvClipuv :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsCIELuvClipLuv :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsTekHVCClipV :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsTekHVCClipC :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + XcmsTekHVCClipVC :: proc( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32 + ) -> Status --- + // Pre-defined white-point adjustment procedures + XcmsCIELabWhiteShiftColors :: proc( + ctx: XcmsCCC, + initial_white_point: ^XcmsColor, + target_white_point: ^XcmsColor, + target_format: XcmsColorFormat, + colors: [^]XcmsColor, + ncolors: u32, + compression: [^]b32 + ) -> Status --- + XcmsCIELuvWhiteShiftColors :: proc( + ctx: XcmsCCC, + initial_white_point: ^XcmsColor, + target_white_point: ^XcmsColor, + target_format: XcmsColorFormat, + colors: [^]XcmsColor, + ncolors: u32, + compression: [^]b32 + ) -> Status --- + XcmsTekHVCWhiteShiftColors :: proc( + ctx: XcmsCCC, + initial_white_point: ^XcmsColor, + target_white_point: ^XcmsColor, + target_format: XcmsColorFormat, + colors: [^]XcmsColor, + ncolors: u32, + compression: [^]b32 + ) -> Status --- + // Color querying + XcmsQueryBlack :: proc( + ccc: XcmsCCC, + format: XcmsColorFormat, + color: ^XcmsColor + ) -> Status --- + XcmsQueryBlue :: proc( + ccc: XcmsCCC, + format: XcmsColorFormat, + color: ^XcmsColor + ) -> Status --- + XcmsQueryGreen :: proc( + ccc: XcmsCCC, + format: XcmsColorFormat, + color: ^XcmsColor + ) -> Status --- + XcmsQueryRed :: proc( + ccc: XcmsCCC, + format: XcmsColorFormat, + color: ^XcmsColor + ) -> Status --- + XcmsQueryWhite :: proc( + ccc: XcmsCCC, + format: XcmsColorFormat, + color: ^XcmsColor + ) -> Status --- + // CIELab queries + XcmsCIELabQueryMaxC :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + lstar: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsCIELabQueryMaxL :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + chroma: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsCIELabQueryMaxLC :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsCIELabQueryMinL :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + chroma: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + // CIEluv queries + XcmsCIELuvQueryMaxC :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + lstar: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsCIELuvQueryMaxL :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + chroma: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsCIELuvQueryMaxLC :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsCIELuvQueryMinL :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + chroma: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + // TexHVX queries + XcmsTekHVCQueryMaxC :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + value: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsTekHVCQueryMaxV :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + chroma: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsTekHVCQueryMaxVC :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + XcmsTekHVCQueryMaxVSamples :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + colors: [^]XcmsColor, + nsamples: u32 + ) -> Status --- + XcmsTekHVCQueryMinV :: proc( + ccc: XcmsCCC, + hue: XcmsFloat, + chroma: XcmsFloat, + color: ^XcmsColor + ) -> Status --- + // Graphics context functions + XCreateGC :: proc( + display: ^Display, + drawable: Drawable, + mask: GCAttributeMask, + attr: ^XGCValues + ) -> GC --- + XCopyGC :: proc( + display: ^Display, + src: GC, + dst: GC, + mask: GCAttributeMask + ) --- + XChangeGC :: proc( + display: ^Display, + gc: GC, + mask: GCAttributeMask, + values: ^XGCValues + ) --- + XGetGCValues :: proc( + display: ^Display, + gc: GC, + mask: GCAttributeMask, + values: ^XGCValues + ) -> Status --- + XFreeGC :: proc(display: ^Display, gc: GC) --- + XGCContextFromGC :: proc(gc: GC) -> GContext --- + XFlushGC :: proc(display: ^Display, gc: GC) --- + // Convenience routines for GC + XSetState :: proc( + display: ^Display, + gc: GC, + fg: uint, + bg: uint, + fn: GCFunction, + pmask: uint + ) --- + XSetForeground :: proc( + display: ^Display, + gc: GC, + fg: uint + ) --- + XSetBackground :: proc( + display: ^Display, + gc: GC, + bg: uint + ) --- + XSetFunction :: proc( + display: ^Display, + gc: GC, + fn: GCFunction + ) --- + XSetPlaneMask :: proc( + display: ^Display, + gc: GC, + pmask: uint + ) --- + XSetLineAttributes :: proc( + display: ^Display, + gc: GC, + width: u32, + line_style: LineStyle, + cap_style: CapStyle, + join_style: JoinStyle + ) --- + XSetDashes :: proc( + display: ^Display, + gc: GC, + dash_offs: i32, + dash_list: [^]i8, + n: i32 + ) --- + XSetFillStyle :: proc( + display: ^Display, + gc: GC, + style: FillStyle + ) --- + XSetFillRule :: proc( + display: ^Display, + gc: GC, + rule: FillRule + ) --- + XQueryBestSize :: proc( + display: ^Display, + class: i32, + which: Drawable, + width: u32, + height: u32, + out_width: ^u32, + out_height: ^u32 + ) -> Status --- + XQueryBestTile :: proc( + display: ^Display, + which: Drawable, + width: u32, + height: u32, + out_width: ^u32, + out_height: ^u32 + ) -> Status --- + XQueryBestStripple :: proc( + display: ^Display, + which: Drawable, + width: u32, + height: u32, + out_width: u32, + out_height: u32 + ) -> Status --- + XSetTile :: proc(display: ^Display, gc: GC, tile: Pixmap) --- + XSetStripple :: proc(display: ^Display, gc: GC, stripple: Pixmap) --- + XSetTSOrigin :: proc(display: ^Display, gc: GC, x: i32, y: i32) --- + XSetFont :: proc(display: ^Display, gc: GC, font: Font) --- + XSetClipOrigin :: proc(display: ^Display, gc: GC, x: i32, y: i32) --- + XSetClipMask :: proc(display: ^Display, gc: GC, pixmap: Pixmap) --- + XSetClipRectangles :: proc( + display: ^Display, + gc: GC, + x: i32, + y: i32, + rects: [^]XRectangle, + n: i32, + ordering: i32 + ) --- + XSetArcMode :: proc(display: ^Display, gc: GC, mode: ArcMode) --- + XSetSubwindowMode :: proc(display: ^Display, gc: GC, mode: SubwindowMode) --- + XSetGraphicsExposures :: proc(display: ^Display, gc: GC, exp: b32) --- + // Graphics functions + XClearArea :: proc( + display: ^Display, + window: Window, + x: i32, + y: i32, + width: u32, + height: u32, + exp: b32 + ) --- + XClearWindow :: proc( + display: ^Display, + window: Window + ) --- + XCopyArea :: proc( + display: ^Display, + src: Drawable, + dst: Drawable, + gc: GC, + src_x: i32, + src_y: i32, + width: u32, + height: u32, + dst_x: i32, + dst_y: i32 + ) --- + XCopyPlane :: proc( + display: ^Display, + src: Drawable, + dst: Drawable, + gc: GC, + src_x: i32, + src_y: i32, + width: u32, + height: u32, + dst_x: i32, + dst_y: i32, + plane: uint + ) --- + // Drawing lines, points, rectangles and arc + XDrawPoint :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32 + ) --- + XDrawPoints :: proc( + display: Display, + drawable: Drawable, + gc: GC, + point: [^]XPoint, + npoints: i32, + mode: CoordMode + ) --- + XDrawLine :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x1: i32, + y1: i32, + x2: i32, + y2: i32 + ) --- + XDrawLines :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + points: [^]XPoint, + npoints: i32 + ) --- + XDrawSegments :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + segs: [^]XSegment, + nsegs: i32 + ) --- + XDrawRectangle :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32 + ) --- + XDrawRectangles :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + rects: [^]XRectangle, + nrects: i32 + ) --- + XDrawArc :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32, + angle1: i32, + angle2: i32 + ) --- + XDrawArcs :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + arcs: [^]XArc, + narcs: i32 + ) --- + // Filling areas + XFillRectangle :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32 + ) --- + XFillRectangles :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + rects: [^]XRectangle, + nrects: i32 + ) --- + XFillPolygon :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + points: [^]XPoint, + npoints: i32, + shape: Shape, + mode: CoordMode + ) --- + XFillArc :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32, + angle1: i32, + angle2: i32 + ) --- + XFillArcs :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + arcs: [^]XArc, + narcs: i32 + ) --- + // Font metrics + XLoadFont :: proc(display: ^Display, name: cstring) -> Font --- + XQueryFont :: proc(display: ^Display, id: XID) -> ^XFontStruct --- + XLoadQueryFont :: proc(display: ^Display, name: cstring) -> ^XFontStruct --- + XFreeFont :: proc(display: ^Display, font_struct: ^XFontStruct) --- + XGetFontProperty :: proc(font_struct: ^XFontStruct, atom: Atom, ret: ^uint) -> b32 --- + XUnloadFont :: proc(display: ^Display, font: Font) --- + XListFonts :: proc(display: ^Display, pat: cstring, max: i32, count: ^i32) -> [^]cstring --- + XFreeFontNames :: proc(display: ^Display, list: [^]cstring) --- + XListFontsWithInfo :: proc( + display: ^Display, + pat: cstring, + max: i32, + count: ^i32, + info: ^[^]XFontStruct + ) -> [^]cstring --- + XFreeFontInfo :: proc(names: [^]cstring, info: [^]XFontStruct, count: i32) --- + // Computing character string sizes + XTextWidth :: proc(font_struct: ^XFontStruct, string: [^]u8, count: i32) -> i32 --- + XTextWidth16 :: proc(font_struct: ^XFontStruct, string: [^]XChar2b, count: i32) -> i32 --- + XTextExtents :: proc( + font_struct: ^XFontStruct, + string: [^]u8, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct + ) --- + XTextExtents16 :: proc( + font_struct: ^XFontStruct, + string: [^]XChar2b, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct + ) --- + XQueryTextExtents :: proc( + display: ^Display, + font_id: XID, + string: [^]u8, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct + ) --- + XQueryTextExtents16 :: proc( + display: ^Display, + font_id: XID, + string: [^]XChar2b, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct + ) --- + // Drawing complex text + XDrawText :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + items: XTextItem, + nitems: i32 + ) --- + XDrawText16 :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + items: XTextItem16, + nitems: i32 + ) --- + // Drawing text characters + XDrawString :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]u8, + length: i32 + ) --- + XDrawString16 :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]XChar2b, + length: i32 + ) --- + XDrawImageString :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]u8, + length: i32 + ) --- + XDrawImageString16 :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]XChar2b, + length: i32 + ) --- + // Transferring images between client and server + XInitImage :: proc(image: ^XImage) -> Status --- + XPutImage :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + image: XImage, + src_x: i32, + src_y: i32, + dst_x: i32, + dst_y: i32, + width: u32, + height: u32 + ) --- + XGetImage :: proc( + display: ^Display, + drawable: Drawable, + x: i32, + y: i32, + width: u32, + height: u32, + mask: uint, + format: ImageFormat + ) -> ^XImage --- + XGetSubImage :: proc( + display: ^Display, + drawable: Drawable, + src_x: i32, + src_y: i32, + width: u32, + height: u32, + mask: uint, + format: ImageFormat, + dst: ^XImage, + dst_x: i32, + dst_y: i32 + ) -> ^XImage --- + // Window and session manager functions + XReparentWindow :: proc( + display: ^Display, + window: Window, + parent: Window, + x: i32, + y: i32 + ) --- + XChangeSaveSet :: proc( + display: ^Display, + window: Window, + mode: SaveSetChangeMode + ) --- + XAddToSaveSet :: proc( + display: ^Display, + window: Window + ) --- + XRemoveFromSaveSet :: proc( + display: ^Display, + window: Window + ) --- + // Managing installed colormaps + XInstallColormap :: proc(display: ^Display, colormap: Colormap) --- + XUninstallColormap :: proc(display: ^Display, colormap: Colormap) --- + XListInstalledColormaps :: proc(display: ^Display, window: Window, n: ^i32) -> [^]Colormap --- + // Setting and retrieving font search paths + XSetFontPath :: proc(display: ^Display, dirs: [^]cstring, ndirs: i32) --- + XGetFontPath :: proc(display: ^Display, npaths: ^i32) -> [^]cstring --- + XFreeFontPath :: proc(list: [^]cstring) --- + // Grabbing the server + XGrabServer :: proc(display: ^Display) --- + XUngrabServer :: proc(display: ^Display) --- + // Killing clients + XKillClient :: proc(display: ^Display, resource: XID) --- + // Controlling the screen saver + XSetScreenSaver :: proc( + display: ^Display, + timeout: i32, + interval: i32, + blanking: ScreenSaverBlanking, + exposures: ScreenSavingExposures + ) --- + XForceScreenSaver :: proc(display: ^Display, mode: ScreenSaverForceMode) --- + XActivateScreenSaver :: proc(display: ^Display) --- + XResetScreenSaver :: proc(display: ^Display) --- + XGetScreenSaver :: proc( + display: ^Display, + timeout: ^i32, + interval: ^i32, + blanking: ^ScreenSaverBlanking, + exposures: ^ScreenSavingExposures + ) --- + // Controlling host address + XAddHost :: proc(display: ^Display, addr: ^XHostAddress) --- + XAddHosts :: proc(display: ^Display, hosts: [^]XHostAddress, nhosts: i32) --- + XListHosts :: proc(display: ^Display, nhosts: ^i32, state: [^]b32) -> [^]XHostAddress --- + XRemoveHost :: proc(display: ^Display, host: XHostAddress) --- + XRemoveHosts :: proc(display: ^Display, hosts: [^]XHostAddress, nhosts: i32) --- + // Access control list + XSetAccessControl :: proc(display: ^Display, mode: AccessControlMode) --- + XEnableAccessControl :: proc(display: ^Display) --- + XDisableAccessControl :: proc(display: ^Display) --- + // Events + XSelectInput :: proc(display: ^Display, window: Window, mask: EventMask) --- + XFlush :: proc(display: ^Display) --- + XSync :: proc(display: ^Display) --- + XEventsQueued :: proc(display: ^Display, mode: EventQueueMode) -> i32 --- + XPending :: proc(display: ^Display) -> i32 --- + XNextEvent :: proc(display: ^Display, event: ^XEvent) --- + XPeekEvent :: proc(display: ^Display, event: ^XEvent) --- + // Selecting events using a predicate procedure + XIfEvent :: proc( + display: ^Display, + event: ^XEvent, + predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, + ctx: rawptr + ) --- + XCheckIfEvent :: proc( + display: ^Display, + event: ^XEvent, + predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, + arg: rawptr + ) -> b32 --- + XPeekIfEvent :: proc( + display: ^Display, + event: ^XEvent, + predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, + ctx: rawptr + ) --- + // Selecting events using a window or event mask + XWindowEvent :: proc( + display: ^Display, + window: Window, + mask: EventMask, + event: ^XEvent + ) --- + XCheckWindowEvent :: proc( + display: ^Display, + window: Window, + mask: EventMask, + event: ^XEvent + ) -> b32 --- + XMaskEvent :: proc( + display: ^Display, + mask: EventMask, + event: ^XEvent + ) --- + XCheckMaskEvent :: proc( + display: ^Display, + mask: EventMask, + event: ^XEvent + ) -> b32 --- + XCheckTypedEvent :: proc( + display: ^Display, + type: EventType, + event: ^XEvent + ) -> b32 --- + XCheckTypedWindowEvent :: proc( + display: ^Display, + window: Window, + type: EventType, + event: ^XEvent + ) -> b32 --- + // Putting events back + XPutBackEvent :: proc( + display: ^Display, + event: ^XEvent + ) --- + // Sending events to other applications + XSendEvent :: proc( + display: ^Display, + window: Window, + propagate: b32, + mask: EventMask, + event: ^XEvent + ) -> Status --- + // Getting the history of pointer motion + XDisplayMotionBufferSize :: proc(display: ^Display) -> uint --- + XGetMotionEvents :: proc( + display: ^Display, + window: Window, + start: Time, + stop: Time, + nevents: ^i32 + ) -> [^]XTimeCoord --- + // Enabling or disabling synchronization + XSetAfterFunction :: proc( + display: ^Display, + procedure: #type proc "c" (display: ^Display) -> i32 + ) -> i32 --- + XSynchronize :: proc( + display: ^Display, + onoff: b32 + ) -> i32 --- + // Error handling + XSetErrorHandler :: proc( + handler: #type proc "c" (display: ^Display, event: ^XErrorEvent) -> i32 + ) -> i32 --- + XGetErrorText :: proc( + display: ^Display, + code: i32, + buffer: [^]u8, + size: i32 + ) --- + XGetErrorDatabaseText :: proc( + display: ^Display, + name: cstring, + message: cstring, + default_string: cstring, + buffer: [^]u8, + size: i32 + ) --- + XDisplayName :: proc(string: cstring) -> cstring --- + XSetIOErrorHandler :: proc( + handler: #type proc "c" (display: ^Display) -> i32 + ) -> i32 --- + // Pointer grabbing + XGrabPointer :: proc( + display: ^Display, + grab_window: Window, + owner_events: b32, + mask: EventMask, + pointer_mode: GrabMode, + keyboard_mode: GrabMode, + confine_to: Window, + cursor: Cursor, + time: Time + ) -> i32 --- + XUngrabPointer :: proc( + display: ^Display, + time: Time + ) -> i32 --- + XChangeActivePointerGrab :: proc( + display: ^Display, + event_mask: EventMask, + cursor: Cursor, + time: Time + ) --- + XGrabButton :: proc( + display: ^Display, + button: u32, + modifiers: InputMask, + grab_window: Window, + owner_events: b32, + event_mask: EventMask, + pointer_mode: GrabMode, + keyboard_mode: GrabMode, + confine_to: Window, + cursor: Cursor + ) --- + XUngrabButton :: proc( + display: ^Display, + button: u32, + modifiers: InputMask, + grab_window: Window + ) --- + XGrabKeyboard :: proc( + display: ^Display, + grab_window: Window, + owner_events: b32, + pointer_mode: GrabMode, + keyboard_mode: GrabMode, + time: Time + ) -> i32 --- + XUngrabKeyboard :: proc( + display: ^Display, + time: Time + ) --- + XGrabKey :: proc( + display: ^Display, + keycode: i32, + modifiers: InputMask, + grab_window: Window, + owner_events: b32, + pointer_mode: GrabMode, + keyboard_mode: GrabMode + ) --- + XUngrabKey :: proc( + display: ^Display, + keycode: i32, + modifiers: InputMask, + grab_window: Window + ) --- + // Resuming event processing + XAllowEvents :: proc(display: ^Display, evend_mode: AllowEventsMode, time: Time) --- + // Moving the pointer + XWarpPointer :: proc( + display: ^Display, + src_window: Window, + dst_window: Window, + src_x: i32, + src_y: i32, + src_width: u32, + src_height: u32, + dst_x: i32, + dst_y: i32 + ) --- + // Controlling input focus + XSetInputFocus :: proc( + display: ^Display, + focus: Window, + revert_to: FocusRevert, + time: Time + ) --- + XGetInputFocus :: proc( + display: ^Display, + focus: ^Window, + revert_to: ^FocusRevert + ) --- + // Manipulating the keyboard and pointer settings + XChangeKeyboardControl :: proc( + display: ^Display, + mask: KeyboardControlMask, + values: ^XKeyboardControl + ) --- + XGetKeyboardControl :: proc( + display: ^Display, + values: ^XKeyboardState + ) --- + XAutoRepeatOn :: proc(display: ^Display) --- + XAutoRepeatOff :: proc(display: ^Display) --- + XBell :: proc(display: ^Display, percent: i32) --- + XQueryKeymap :: proc(display: ^Display, keys: [^]u32) --- + XSetPointerMapping :: proc(display: ^Display, map_should_not_be_a_keyword: [^]u8, nmap: i32) -> i32 --- + XGetPointerMapping :: proc(display: ^Display, map_should_not_be_a_keyword: [^]u8, nmap: i32) -> i32 --- + XChangePointerControl :: proc( + display: ^Display, + do_accel: b32, + do_threshold: b32, + accel_numerator: i32, + accel_denominator: i32, + threshold: i32 + ) --- + XGetPointerControl :: proc( + display: ^Display, + accel_numerator: ^i32, + accel_denominator: ^i32, + threshold: ^i32 + ) --- + // Manipulating the keyboard encoding + XDisplayKeycodes :: proc( + display: ^Display, + min_keycodes: ^i32, + max_keycodes: ^i32 + ) --- + XGetKeyboardMapping :: proc( + display: ^Display, + first: KeyCode, + count: i32, + keysyms_per: ^i32 + ) -> ^KeySym --- + XChangeKeyboardMapping :: proc( + display: ^Display, + first: KeyCode, + keysyms_per: i32, + keysyms: [^]KeySym, + num_codes: i32 + ) --- + XNewModifiermap :: proc(max_keys_per_mode: i32) -> ^XModifierKeymap --- + XInsertModifiermapEntry :: proc( + modmap: ^XModifierKeymap, + keycode_entry: KeyCode, + modifier: i32 + ) -> ^XModifierKeymap --- + XDeleteModifiermapEntry :: proc( + modmap: ^XModifierKeymap, + keycode_entry: KeyCode, + modifier: i32 + ) -> ^XModifierKeymap --- + XFreeModifiermap :: proc(modmap: ^XModifierKeymap) --- + XSetModifierMapping :: proc(display: ^Display, modmap: ^XModifierKeymap) -> i32 --- + XGetModifierMapping :: proc(display: ^Display) -> ^XModifierKeymap --- +} diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin new file mode 100644 index 000000000..bb2f16604 --- /dev/null +++ b/vendor/x11/xlib/xlib_types.odin @@ -0,0 +1,1307 @@ +//+build linux, freebsd, openbsd +package xlib + +// Since this is a unix-only library we make a few simplifying assumptions +import "core:c" +#assert(size_of(int) == size_of(c.long)) +#assert(size_of(uint) == size_of(c.ulong)) +#assert(size_of(i32) == size_of(c.int)) +#assert(size_of(u32) == size_of(c.uint)) + +/* ---- X11/X.h ------------------------------------------------------------*/ + +XID :: distinct uint +Mask :: distinct uint +Atom :: distinct uint +VisualID :: distinct uint +Time :: distinct uint + +Window :: XID +Drawable :: XID +Font :: XID +Pixmap :: XID +Cursor :: XID +Colormap :: XID +GContext :: XID + +KeyCode :: u8 + +/* ---- X11/Xlib.h ---------------------------------------------------------*/ + +XExtData :: struct { + number: i32, + next: ^XExtData, + free_private: #type proc "c" (extension: ^XExtData) -> Status, + private_data: rawptr, +} + +XExtCodes :: struct { + extension: i32, + major_opcode: i32, + first_event: i32, + first_error: i32, +} + +XPixmapFormatValues :: struct { + depth: i32, + bits_per_pixel: i32, + scanline_pad: i32, +} + +XGCValues :: struct { + function: GCFunction, + plane_mask: uint, + foreground: uint, + background: uint, + line_width: i32, + line_style: LineStyle, + cap_style: CapStyle, + join_style: JoinStyle, + fill_style: FillStyle, + fill_rule: FillRule, + arc_mode: ArcMode, + tile: Pixmap, + stipple: Pixmap, + ts_x_origin: i32, + ts_y_origin: i32, + font: Font, + subwindow_mode: SubwindowMode, + graphics_exposures: b32, + clip_x_origin: i32, + clip_y_origin: i32, + clip_mask: Pixmap, + dash_offset: i32, + dashes: i8, +} + +GC :: distinct rawptr + +Visual :: struct { + ext_data: ^XExtData, + visualid: VisualID, + class: i32, + red_mask: uint, + green_mask: uint, + blue_mask: uint, + bits_per_rgb: i32, + map_entries: i32, +} + +Depth :: struct { + depth: i32, + nvisuals: i32, + visuals: ^Visual, +} + +XDisplay :: distinct struct {} + +Screen :: struct { + ext_data: ^XExtData, + display: ^XDisplay, + root: Window, + width: i32, + height: i32, + mwidth: i32, + mheight: i32, + ndepths: i32, + depths: ^Depth, + root_depth: i32, + root_visual: ^Visual, + default_gc: GC, + cmap: Colormap, + white_pixel: uint, + black_pixel: uint, + max_maps: i32, + min_maps: i32, + backing_store: i32, + save_unders: i32, + root_input_mask: int, +} + +ScreenFormat :: struct { + ext_data: ^XExtData, + depth: i32, + bits_per_pixel: i32, + scanline_pad: i32, +} + +XSetWindowAttributes :: struct { + background_pixmap: Pixmap, + background_pixel: uint, + border_pixmap: Pixmap, + border_pixel: uint, + bit_gravity: Gravity, + win_gravity: Gravity, + backing_store: BackingStore, + backing_planes: uint, + backing_pixel: uint, + save_under: b32, + event_mask: EventMask, + do_not_propagate_mask: EventMask, + override_redirect: b32, + colormap: Colormap, + cursor: Cursor, +} + +XWindowAttributes :: struct { + x: i32, + y: i32, + width: i32, + height: i32, + border_width: i32, + depth: i32, + visual: ^Visual, + root: Window, + class: WindowClass, + bit_gravity: Gravity, + win_gravity: Gravity, + backing_store: BackingStore, + backing_planes: uint, + backing_pixel: uint, + save_under: b32, + colormap: Colormap, + map_installed: b32, + map_state: WindowMapState, + all_event_masks: EventMask, + your_event_mask: EventMask, + do_not_propagate_mask: EventMask, + override_redirect: b32, + screen: ^Screen, +} + +XHostAddress :: struct { + family: i32, + length: i32, + address: rawptr, +} + +XServerInterpretedAddress :: struct { + typelength: i32, + valuelength: i32, + type: [^]u8, + value: [^]u8, +} + +XImage :: struct { + width: i32, + height: i32, + xoffset: i32, + format: ImageFormat, + data: rawptr, + byte_order: i32, + bitmap_unit: i32, + bitmap_bit_order: ByteOrder, + bitmap_pad: i32, + depth: i32, + bytes_per_line: i32, + bits_per_pixel: i32, + red_mask: uint, + green_mask: uint, + blue_mask: uint, + obdata: rawptr, + f: struct { + create_image: proc "c" ( + display: ^Display, + visual: ^Visual, + depth: u32, + format: i32, + offset: i32, + data: rawptr, + width: u32, + height: u32, + pad: i32, + stride: i32) -> ^XImage, + destroy_image: proc "c" (image: ^XImage) -> i32, + get_pixel: proc "c" (image: ^XImage) -> uint, + put_pixel: proc "c" (image: ^XImage, x: i32, y: i32, pixel: uint) -> i32, + sub_image: proc "c" (image: ^XImage, x: i32, y: i32, w: u32, h: u32) -> ^XImage, + add_pixel: proc "c" (image: ^XImage, val: int) -> i32, + }, +} + +XWindowChanges :: struct { + x: i32, + y: i32, + width: i32, + height: i32, + border_width: i32, + sibling: Window, + stack_mode: WindowStacking, +} + +XColor :: struct { + pixel: uint, + red: u16, + green: u16, + blue: u16, + flags: u8, + pad: u8, +} + +XSegment :: struct { + x1: i16, + y1: i16, + x2: i16, + y2: i16, +} + +XPoint :: struct { + x: i16, + y: i16, +} + +XRectangle :: struct { + x: i16, + y: i16, + width: u16, + height: u16, +} + +XArc :: struct { + x: i16, + y: i16, + width: u16, + height: u16, + angle1: i16, + angle2: i16, +} + +XKeyboardControl :: struct { + key_click_percent: i32, + bell_percent: i32, + bell_pitch: i32, + bell_duration: i32, + led: i32, + led_mode: KeyboardLedMode, + key: i32, + auto_repeat_mode: KeyboardAutoRepeatMode, +} + +XKeyboardState :: struct { + key_click_percent: i32, + bell_percent: i32, + bell_pitch: u32, + bell_duration: u32, + led_mask: uint, + global_auto_repeat: i32, + auto_repeats: [32]u8, +} + +XTimeCoord :: struct { + time: Time, + x: i16, + y: i16, +} + +XModifierKeymap :: struct { + max_keypermod: i32, + modifiermap: ^KeyCode, +} + +Display :: distinct struct {} + +XKeyEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + root: Window, + subwindow: Window, + time: Time, + x: i32, + y: i32, + x_root: i32, + y_root: i32, + state: InputMask, + keycode: u32, + same_screen: b32, +} + +XKeyPressedEvent :: XKeyEvent +XKeyReleasedEvent :: XKeyEvent + +XButtonEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + root: Window, + subwindow: Window, + time: Time, + x: i32, + y: i32, + x_root: i32, + y_root: i32, + state: InputMask, + button: u32, + same_screen: b32, +} + +XButtonPressedEvent :: XButtonEvent +XButtonReleasedEvent :: XButtonEvent + +XMotionEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + root: Window, + subwindow: Window, + time: Time, + x: i32, + y: i32, + x_root: i32, + y_root: i32, + state: InputMask, + is_hint: b8, + same_screen: b32, +} + +XPointerMovedEvent :: XMotionEvent; + +XCrossingEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + root: Window, + subwindow: Window, + time: Time, + x: i32, + y: i32, + x_root: i32, + y_root: i32, + mode: NotifyMode, + detail: NotifyDetail, + same_screen: b32, + focus: i32, + state: InputMask, +} + +XEnterWindowEvent :: XCrossingEvent +XLeaveWindowEvent :: XCrossingEvent + +XFocusChangeEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + mode: NotifyMode, + detail: NotifyDetail, +} + +XFocusInEvent :: XFocusChangeEvent +XFocusOutEvent :: XFocusChangeEvent + +XKeymapEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + key_vector: [32]u8, +} + +XExposeEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + x: i32, + y: i32, + width: i32, + height: i32, + count: i32, +} + +XGraphicsExposeEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + drawable: Drawable, + x: i32, + y: i32, + width: i32, + height: i32, + count: i32, + major_code: i32, + minor_code: i32, +} + +XNoExposeEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + drawable: Drawable, + major_code: i32, + minor_code: i32, +} + +XVisibilityEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + state: VisibilityState, +} + +XCreateWindowEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + parent: Window, + window: Window, + x: i32, + y: i32, + width: i32, + height: i32, + border_width: i32, + override_redirect: b32, +} + +XDestroyWindowEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + event: Window, + window: Window, +} + +XUnmapEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + event: Window, + window: Window, + from_configure: b32, +} + +XMapEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + event: Window, + window: Window, + override_redirect: b32, +} + +XMapRequestEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + parent: Window, + window: Window, +} + +XReparentEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + event: Window, + window: Window, + parent: Window, + x: i32, + y: i32, + override_redirect: b32, +} + +XConfigureEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + event: Window, + window: Window, + x: i32, + y: i32, + width: i32, + height: i32, + border_width: i32, + above: Window, + override_redirect: b32, +} + +XGravityEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + event: Window, + window: Window, + x: i32, + y: i32, +} + +XResizeRequestEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + width: i32, + height: i32, +} + +XConfigureRequestEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + parent: Window, + window: Window, + x: i32, + y: i32, + width: i32, + height: i32, + border_width: i32, + above: Window, + detail: WindowStacking, + value_mask: uint, +} + +XCirculateEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + event: Window, + window: Window, + place: CirculationRequest, +} + +XCirculateRequestEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + parent: Window, + window: Window, + place: CirculationRequest, +} + +XPropertyEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + atom: Atom, + time: Time, + state: PropertyState, +} + +XSelectionClearEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + selection: Atom, + time: Time, +} + +XSelectionRequestEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + owner: Window, + requestor: Window, + selection: Atom, + target: Atom, + property: Atom, + time: Time, +} + +XSelectionEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + requestor: Window, + selection: Atom, + target: Atom, + property: Atom, + time: Time, +} + +XColormapEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + colormap: Colormap, + new: b32, + state: ColormapState, +} + +XClientMessageEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + message_type: Atom, + format: i32, + data: struct #raw_union { + b: [20]i8, + s: [10]i16, + l: [5]int, + }, +} + +XMappingEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, + request: MappingRequest, + first_keycode: i32, + count: i32, +} + +XErrorEvent :: struct { + type: EventType, + display: ^Display, + resourceid: XID, + serial: uint, + error_code: u8, + request_code: u8, + minor_code: u8, +} + +XAnyEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + window: Window, +} + +XGenericEvent :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: ^Display, + extension: i32, + evtype: i32, +} + +XGenericEventCookie :: struct { + type: EventType, + serial: uint, + send_event: b32, + display: Display, + extension: i32, + evtype: i32, + cookie: u32, + data: rawptr, +} + +XEvent :: struct #raw_union { + type: EventType, + xany: XAnyEvent, + xkey: XKeyEvent, + xbutton: XButtonEvent, + xmotion: XMotionEvent, + xcrossing: XCrossingEvent, + xfocus: XFocusChangeEvent, + xexpose: XExposeEvent, + xgraphicsexpose: XGraphicsExposeEvent, + xnoexpose: XNoExposeEvent, + xvisibility: XVisibilityEvent, + xcreatewindow: XCreateWindowEvent, + xdestroywindow: XDestroyWindowEvent, + xunmap: XUnmapEvent, + xmap: XMapEvent, + xmaprequest: XMapRequestEvent, + xreparent: XReparentEvent, + xconfigure: XConfigureEvent, + xgravity: XGravityEvent, + xresizerequest: XResizeRequestEvent, + xconfigurerequest: XConfigureRequestEvent, + xcirculate: XCirculateEvent, + xcirculaterequest: XCirculateRequestEvent, + xproperty: XPropertyEvent, + xselectionclear: XSelectionClearEvent, + xselectionrequest: XSelectionRequestEvent, + xselection: XSelectionEvent, + xcolormap: XColormapEvent, + xclient: XClientMessageEvent, + xmapping: XMappingEvent, + xerror: XErrorEvent, + xkeymap: XKeymapEvent, + xgeneric: XGenericEvent, + xcookie: XGenericEventCookie, + _: [24]int, +} + +XCharStruct :: struct { + lbearing: i16, + rbearing: i16, + width: i16, + ascent: i16, + descent: i16, + attributes: u16, +} + +XFontProp :: struct { + name: Atom, + card32: uint, +} + +XFontStruct :: struct { + ext_data: ^XExtData, + fid: Font, + direction: u32, + min_char_or_byte2: u32, + max_char_or_byte2: u32, + min_byte1: u32, + max_byte1: u32, + all_chars_exist: i32, + default_char: u32, + n_properties: i32, + properties: ^XFontProp, + min_bounds: XCharStruct, + max_bounds: XCharStruct, + per_char: ^XCharStruct, + ascent: i32, + descent: i32, +} + +XTextItem :: struct { + chars: [^]u8, + nchars: i32, + delta: i32, + font: Font, +} + +XChar2b :: struct { + byte1: u8, + byte2: u8, +} + +XTextItem16 :: struct { + chars: ^XChar2b, + nchars: i32, + delta: i32, + font: Font, +} + +XEDataObject :: struct #raw_union { + display: ^Display, + gc: GC, + visual: ^Visual, + screen: ^Screen, + pixmap_format: ^ScreenFormat, + font: ^XFontStruct, +} + +XFontSetExtents :: struct { + max_ink_extent: XRectangle, + max_logical_extent: XRectangle, +} + +XOM :: distinct rawptr +XOC :: distinct rawptr +XFontSet :: XOC + +XmbTextItem :: struct { + chars: [^]u8, + nchars: i32, + delta: i32, + font_set: XFontSet, +} + +XwcTextItem :: struct { + chars: [^]rune, + nchars: i32, + delta: i32, + font_set: XFontSet, +} + +XOMCharSetList :: struct { + charset_count: i32, + charset_list: [^]cstring, +} + +XOrientation :: enum i32 { + XOMOrientation_LTR_TTB = 0, + XOMOrientation_RTL_TTB = 1, + XOMOrientation_TTB_LTR = 2, + XOMOrientation_TTB_RTL = 3, + XOMOrientation_Context = 4, +} + +XOMOrientation :: struct { + num_orientation: i32, + orientation: [^]XOrientation, +} + +XOMFontInfo :: struct { + num_font: i32, + font_struct_list: [^]^XFontStruct, + font_name_list: [^]cstring, +} + +XIM :: distinct rawptr +XIC :: distinct rawptr + +XIMProc :: #type proc "c" (xim: XIM, client_data: rawptr, call_data: rawptr) +XICProc :: #type proc "c" (xim: XIM, client_data: rawptr, call_data: rawptr) +XIDProc :: #type proc "c" (xim: XIM, client_data: rawptr, call_data: rawptr) + +XIMStyle :: uint + +XIMStyles :: struct { + count_styles: u16, + supported_styles: [^]XIMStyle, +} + +XVaNestedList :: distinct rawptr + +XIMCallback :: struct { + client_data: rawptr, + callback: XIMProc, +} + +XICCallback :: struct { + client_data: rawptr, + callback: XICProc, +} + +XIMFeedback :: uint + +XIMText :: struct { + length: u16, + feedback: ^XIMFeedback, + encoding_is_wchar: b32, + string: struct #raw_union { + multi_byte: [^]u8, + wide_char: [^]rune, + }, +} + +XIMPreeditState :: uint + +XIMPreeditStateNotifyCallbackStruct :: struct { + state: XIMPreeditState, +} + +XIMResetState :: uint + +XIMStringConversionFeedback :: uint + +XIMStringConversionText :: struct { + length: u16, + feedback: ^XIMStringConversionFeedback, + encoding_is_wchar: b32, + string: struct #raw_union { + mbs: [^]u8, + wcs: [^]rune, + }, +} + +XIMStringConversionPosition :: u16 +XIMStringConversionType :: u16 +XIMStringConversionOperation :: u16 + +XIMCaretDirection :: enum i32 { + XIMForwardChar = 0, + XIMBackwardChar = 1, + XIMForwardWord = 2, + XIMBackwardWord = 3, + XIMCaretUp = 4, + XIMCaretDown = 5, + XIMNextLine = 6, + XIMPreviousLine = 7, + XIMLineStart = 8, + XIMLineEnd = 9, + XIMAbsolutePosition = 10, + XIMDontChang = 11, +} + +XIMStringConversionCallbackStruct :: struct { + position: XIMStringConversionPosition, + direction: XIMCaretDirection, + operation: XIMStringConversionOperation, + factor: u16, + text: ^XIMStringConversionText, +} + +XIMPreeditDrawCallbackStruct :: struct { + caret: i32, + chg_first: i32, + chg_length: i32, + text: ^XIMText, +} + +XIMCaretStyle :: enum i32 { + XIMIsInvisible, + XIMIsPrimary, + XIMIsSecondary, +} + +XIMPreeditCaretCallbackStruct :: struct { + position: i32, + direction: XIMCaretDirection, + style: XIMCaretStyle, +} + +XIMStatusDataType :: enum { + XIMTextType, + XIMBitmapType, +} + +XIMStatusDrawCallbackStruct :: struct { + type: XIMStatusDataType, + data: struct #raw_union { + text: ^XIMText, + bitmap: Pixmap, + }, +} + +XIMHotKeyTrigger :: struct { + keysym: KeySym, + modifier: i32, + modifier_mask: i32, +} + +XIMHotKeyTriggers :: struct { + num_hot_key: i32, + key: [^]XIMHotKeyTrigger, +} + +XIMHotKeyState :: uint + +XIMValuesList :: struct { + count_values: u16, + supported_values: [^]cstring, +} + +XConnectionWatchProc :: #type proc "c" ( + display: ^Display, + client_data: rawptr, + fd: i32, + opening: b32, + watch_data: rawptr) + +/* ---- X11/Xcms.h ---------------------------------------------------------*/ + +XcmsColorFormat :: uint + +XcmsFloat :: f64 + +XcmsRGB :: struct { + red: u16, + green: u16, + blue: u16, +} + +XcmsRGBi :: struct { + red: XcmsFloat, + green: XcmsFloat, + blue: XcmsFloat, +} + +XcmsCIEXYZ :: struct { + X: XcmsFloat, + Y: XcmsFloat, + Z: XcmsFloat, +} + +XcmsCIEuvY :: struct { + u_prime: XcmsFloat, + v_prime: XcmsFloat, + Y: XcmsFloat, +} + +XcmsCIExyY :: struct { + x: XcmsFloat, + y: XcmsFloat, + Y: XcmsFloat, +} + +XcmsCIELab :: struct { + L_star: XcmsFloat, + a_star: XcmsFloat, + b_star: XcmsFloat, +} + +XcmsCIELuv :: struct { + L_star: XcmsFloat, + u_star: XcmsFloat, + v_star: XcmsFloat, +} + +XcmsTekHVC :: struct { + H: XcmsFloat, + V: XcmsFloat, + C: XcmsFloat, +} + +XcmsPad :: struct { + _: XcmsFloat, + _: XcmsFloat, + _: XcmsFloat, + _: XcmsFloat, +} + +XcmsColor :: struct { + spec: struct #raw_union { + RGB: XcmsRGB, + RGBi: XcmsRGBi, + CIEXYZ: XcmsCIEXYZ, + CIEuvY: XcmsCIEuvY, + CIExyY: XcmsCIExyY, + CIELab: XcmsCIELab, + CIELuv: XcmsCIELuv, + TekHVC: XcmsTekHVC, + _: XcmsPad, + }, + pixel: uint, + format: XcmsColorFormat, +} + +XcmsPerScrnInfo :: struct { + screenWhitePt: XcmsColor, + functionSet: rawptr, + screenData: rawptr, + state: u8, + _: [3]u8, +} + +XcmsCCC :: distinct rawptr + +XcmsCompressionProc :: #type proc "c" ( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + index: u32, + flags: [^]b32) -> Status + +XcmsWhiteAdjustProc :: #type proc "c" ( + ctx: XcmsCCC, + initial_white_point: ^XcmsColor, + target_white_point: ^XcmsColor, + target_format: XcmsColorFormat, + colors: [^]XcmsColor, + ncolors: u32, + compression: [^]b32) -> Status + +XcmsCCCRec :: struct { + dpy: ^Display, + screenNumber: i32, + visual: ^Visual, + clientWhitePt: XcmsColor, + gamutCompProc: XcmsCompressionProc, + gamutCompClientData: rawptr, + whitePtAdjProc: XcmsWhiteAdjustProc, + whitePtAdjClientData: rawptr, + pPerScrnInfo: ^XcmsPerScrnInfo, +} + +XcmsScreenInitProc :: #type proc "c" ( + display: ^Display, + screen_number: i32, + screen_info: ^XcmsPerScrnInfo) -> i32 + +XcmsScreenFreeProc :: #type proc "c" (screen: rawptr) + +XcmsDDConversionProc :: #type proc "c" ( + ctx: XcmsCCC, + colors: [^]XcmsColor, + ncolors: u32, + compressed: [^]b32) -> i32 + +XcmsDIConversionProc :: #type proc "c" ( + ctx: XcmsCCC, + white_point: ^XcmsColor, + colors: ^XcmsColor, + ncolors: u32) -> i32 + + +XcmsConversionProc :: XcmsDIConversionProc +XcmsFuncListPtr :: [^]XcmsConversionProc + +XcmsParseStringProc :: #type proc "c" (color_string: cstring, color: ^XcmsColor) -> i32 + +XcmsColorSpace :: struct { + prefix: cstring, + id: XcmsColorFormat, + parseString: XcmsParseStringProc, + to_CIEXYZ: XcmsFuncListPtr, + from_CIEXYZ: XcmsFuncListPtr, + inverse_flag: i32, +} + +XcmsFunctionSet :: struct { + DDColorSpaces: [^]^XcmsColorSpace, + screenInitProc: XcmsScreenInitProc, + screenFreeProc: XcmsScreenFreeProc, +} + + +/* ---- X11/Xutil.h --------------------------------------------------------*/ + +XSizeHints :: struct { + flags: int, + x: i32, + y: i32, + width: i32, + height: i32, + min_width: i32, + min_height: i32, + max_width: i32, + max_height: i32, + width_inc: i32, + height_inc: i32, + min_aspect: struct {x,y: i32}, + max_aspect: struct {x,y: i32}, + base_width: i32, + base_height: i32, + win_gravity: i32, +} + +XWMHints :: struct { + flags: int, + input: i32, + initial_state: i32, + icon_pixmap: Pixmap, + icon_window: Window, + icon_x: i32, + icon_y: i32, + icon_mask: Pixmap, + window_group: XID, +} + +XTextProperty :: struct { + value: [^]u8, + encoding: Atom, + format: int, + nitems: uint, +} + +XICCEncodingStyle :: enum i32 { + XStringStyle, + XCompoundTextStyle, + XTextStyle, + XStdICCTextStyle, + XUTF8StringStyle, +} + +XIconSize :: struct { + min_width: i32, + min_height: i32, + max_width: i32, + max_height: i32, + width_inc: i32, + height_inc: i32, +} + +XClassHint :: struct { + res_name: cstring, + res_class: cstring, +} + +XComposeStatus :: struct { + compose_ptr: rawptr, + chars_matched: i32, +} + +Region :: distinct rawptr + +XVisualInfo :: struct { + visual: ^Visual, + visualid: VisualID, + screen: i32, + depth: i32, + class: i32, + red_mask: uint, + green_mask: uint, + blue_mask: uint, + colormap_size: i32, + bits_per_rgb: i32, +} + +XStandardColormap :: struct { + colormap: Colormap, + red_max: uint, + red_mult: uint, + green_max: uint, + green_mult: uint, + blue_max: uint, + blue_mult: uint, + base_pixel: uint, + visualid: VisualID, + killid: XID, +} + +XContext :: i32 + +/* ---- X11/Xresource.h ----------------------------------------------------*/ + +XrmQuark :: i32 +XrmQuarkList :: [^]i32 +XrmString :: cstring + +XrmBinding :: enum i32 { + XrmBindTightly, + XrmBindLoosely, +} + +XrmBindingList :: [^]XrmBinding + +XrmName :: XrmQuark +XrmNameList :: XrmQuarkList +XrmClass :: XrmQuark +XrmClassList :: XrmQuarkList +XrmRepresentation :: XrmQuark + +XrmValue :: struct { + size: u32, + addr: rawptr, +} +XrmValuePtr :: [^]XrmValue + +XrmHashBucket :: distinct rawptr +XrmHashTable :: [^]XrmHashBucket +XrmSearchList :: [^]XrmHashTable +XrmDatabase :: distinct rawptr + +XrmOptionKind :: enum { + XrmoptionNoArg, + XrmoptionIsArg, + XrmoptionStickyArg, + XrmoptionSepArg, + XrmoptionResArg, + XrmoptionSkipArg, + XrmoptionSkipLine, + XrmoptionSkipNArgs, +} + +XrmOptionDescRec :: struct { + option: cstring, + specifier: cstring, + argKind: XrmOptionKind, + value: rawptr, +} + +XrmOptionDescList :: [^]XrmOptionDescRec From 270348b112d0becce7726023b72784066d02306d Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sat, 11 Nov 2023 20:36:38 +1100 Subject: [PATCH 041/160] [core]: Remove `do` keyword from the core library --- .../topological_sort/topological_sort.odin | 12 +- core/math/fixed/fixed.odin | 4 +- core/mem/allocators.odin | 4 +- core/net/addr.odin | 4 +- core/net/socket_linux.odin | 4 +- core/net/url.odin | 12 +- core/odin/ast/clone.odin | 434 +++++++++--------- core/slice/heap/heap.odin | 12 +- core/thread/thread.odin | 24 +- 9 files changed, 273 insertions(+), 237 deletions(-) diff --git a/core/container/topological_sort/topological_sort.odin b/core/container/topological_sort/topological_sort.odin index 314e3e070..f1e9bf57b 100644 --- a/core/container/topological_sort/topological_sort.odin +++ b/core/container/topological_sort/topological_sort.odin @@ -80,11 +80,13 @@ sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) { } } - for root in sorted do for k, _ in relations[root].dependents { - relation := &relations[k] - relation.dependencies -= 1 - if relation.dependencies == 0 { - append(&sorted, k) + for root in sorted { + for k, _ in relations[root].dependents { + relation := &relations[k] + relation.dependencies -= 1 + if relation.dependencies == 0 { + append(&sorted, k) + } } } diff --git a/core/math/fixed/fixed.odin b/core/math/fixed/fixed.odin index 8567fd0ed..5d63bf7be 100644 --- a/core/math/fixed/fixed.odin +++ b/core/math/fixed/fixed.odin @@ -33,7 +33,9 @@ init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) { x.i = Backing(f * (1< ([]byte, Alloc n := bytes extra := p.alignment - (n % p.alignment) n += extra - if n > p.block_size do return nil, .Invalid_Argument + if n > p.block_size { + return nil, .Invalid_Argument + } if n >= p.out_band_size { assert(p.block_allocator.procedure != nil) memory, err := p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc, diff --git a/core/net/addr.odin b/core/net/addr.odin index f0c47e926..508399bf4 100644 --- a/core/net/addr.odin +++ b/core/net/addr.odin @@ -462,7 +462,9 @@ split_port :: proc(endpoint_str: string) -> (addr_or_host: string, port: int, ok // Joins an address or hostname with a port. join_port :: proc(address_or_host: string, port: int, allocator := context.allocator) -> string { addr_or_host, _, ok := split_port(address_or_host) - if !ok do return addr_or_host + if !ok { + return addr_or_host + } b := strings.builder_make(allocator) diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index 590946dff..3760b5d99 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -333,7 +333,9 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := .Send_Timeout, .Receive_Timeout: t, ok := value.(time.Duration) - if !ok do panic("set_option() value must be a time.Duration here", loc) + if !ok { + panic("set_option() value must be a time.Duration here", loc) + } micros := cast(i64) (time.duration_microseconds(t)) timeval_value.microseconds = cast(int) (micros % 1e6) diff --git a/core/net/url.odin b/core/net/url.odin index ef43d6c9f..07b268c75 100644 --- a/core/net/url.odin +++ b/core/net/url.odin @@ -123,7 +123,9 @@ percent_encode :: proc(s: string, allocator := context.allocator) -> string { percent_decode :: proc(encoded_string: string, allocator := context.allocator) -> (decoded_string: string, ok: bool) { b := strings.builder_make(allocator) strings.builder_grow(&b, len(encoded_string)) - defer if !ok do strings.builder_destroy(&b) + defer if !ok { + strings.builder_destroy(&b) + } s := encoded_string @@ -137,7 +139,9 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) - strings.write_string(&b, s[:i]) s = s[i:] - if len(s) == 0 do return // percent without anything after it + if len(s) == 0 { + return // percent without anything after it + } s = s[1:] if s[0] == '%' { @@ -177,7 +181,9 @@ base64url_encode :: proc(data: []byte, allocator := context.allocator) -> string } i := len(out)-1; for ; i >= 0; i -= 1 { - if out[i] != '=' do break; + if out[i] != '=' { + break; + } } return string(out[:i+1]); } diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 79e7a166e..2d85029e8 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -107,226 +107,228 @@ clone_node :: proc(node: ^Node) -> ^Node { reflect.set_union_value(ds, res_ptr_any) } - if res.derived != nil do switch r in res.derived { - case ^Package, ^File: - case ^Bad_Expr: - case ^Ident: - case ^Implicit: - case ^Undef: - case ^Basic_Lit: - case ^Basic_Directive: - case ^Comment_Group: + if res.derived != nil { + switch r in res.derived { + case ^Package, ^File: + case ^Bad_Expr: + case ^Ident: + case ^Implicit: + case ^Undef: + case ^Basic_Lit: + case ^Basic_Directive: + case ^Comment_Group: - case ^Ellipsis: - r.expr = clone(r.expr) - case ^Proc_Lit: - r.type = auto_cast clone(r.type) - r.body = clone(r.body) - case ^Comp_Lit: - r.type = clone(r.type) - r.elems = clone(r.elems) + case ^Ellipsis: + r.expr = clone(r.expr) + case ^Proc_Lit: + r.type = auto_cast clone(r.type) + r.body = clone(r.body) + case ^Comp_Lit: + r.type = clone(r.type) + r.elems = clone(r.elems) - case ^Tag_Expr: - r.expr = clone(r.expr) - case ^Unary_Expr: - r.expr = clone(r.expr) - case ^Binary_Expr: - r.left = clone(r.left) - r.right = clone(r.right) - case ^Paren_Expr: - r.expr = clone(r.expr) - case ^Selector_Expr: - r.expr = clone(r.expr) - r.field = auto_cast clone(r.field) - case ^Implicit_Selector_Expr: - r.field = auto_cast clone(r.field) - case ^Selector_Call_Expr: - r.expr = clone(r.expr) - r.call = auto_cast clone(r.call) - case ^Index_Expr: - r.expr = clone(r.expr) - r.index = clone(r.index) - case ^Matrix_Index_Expr: - r.expr = clone(r.expr) - r.row_index = clone(r.row_index) - r.column_index = clone(r.column_index) - case ^Deref_Expr: - r.expr = clone(r.expr) - case ^Slice_Expr: - r.expr = clone(r.expr) - r.low = clone(r.low) - r.high = clone(r.high) - case ^Call_Expr: - r.expr = clone(r.expr) - r.args = clone(r.args) - case ^Field_Value: - r.field = clone(r.field) - r.value = clone(r.value) - case ^Ternary_If_Expr: - r.x = clone(r.x) - r.cond = clone(r.cond) - r.y = clone(r.y) - case ^Ternary_When_Expr: - r.x = clone(r.x) - r.cond = clone(r.cond) - r.y = clone(r.y) - case ^Or_Else_Expr: - r.x = clone(r.x) - r.y = clone(r.y) - case ^Or_Return_Expr: - r.expr = clone(r.expr) - case ^Or_Branch_Expr: - r.expr = clone(r.expr) - r.label = clone(r.label) - case ^Type_Assertion: - r.expr = clone(r.expr) - r.type = clone(r.type) - case ^Type_Cast: - r.type = clone(r.type) - r.expr = clone(r.expr) - case ^Auto_Cast: - r.expr = clone(r.expr) - case ^Inline_Asm_Expr: - r.param_types = clone(r.param_types) - r.return_type = clone(r.return_type) - r.constraints_string = clone(r.constraints_string) - r.asm_string = clone(r.asm_string) + case ^Tag_Expr: + r.expr = clone(r.expr) + case ^Unary_Expr: + r.expr = clone(r.expr) + case ^Binary_Expr: + r.left = clone(r.left) + r.right = clone(r.right) + case ^Paren_Expr: + r.expr = clone(r.expr) + case ^Selector_Expr: + r.expr = clone(r.expr) + r.field = auto_cast clone(r.field) + case ^Implicit_Selector_Expr: + r.field = auto_cast clone(r.field) + case ^Selector_Call_Expr: + r.expr = clone(r.expr) + r.call = auto_cast clone(r.call) + case ^Index_Expr: + r.expr = clone(r.expr) + r.index = clone(r.index) + case ^Matrix_Index_Expr: + r.expr = clone(r.expr) + r.row_index = clone(r.row_index) + r.column_index = clone(r.column_index) + case ^Deref_Expr: + r.expr = clone(r.expr) + case ^Slice_Expr: + r.expr = clone(r.expr) + r.low = clone(r.low) + r.high = clone(r.high) + case ^Call_Expr: + r.expr = clone(r.expr) + r.args = clone(r.args) + case ^Field_Value: + r.field = clone(r.field) + r.value = clone(r.value) + case ^Ternary_If_Expr: + r.x = clone(r.x) + r.cond = clone(r.cond) + r.y = clone(r.y) + case ^Ternary_When_Expr: + r.x = clone(r.x) + r.cond = clone(r.cond) + r.y = clone(r.y) + case ^Or_Else_Expr: + r.x = clone(r.x) + r.y = clone(r.y) + case ^Or_Return_Expr: + r.expr = clone(r.expr) + case ^Or_Branch_Expr: + r.expr = clone(r.expr) + r.label = clone(r.label) + case ^Type_Assertion: + r.expr = clone(r.expr) + r.type = clone(r.type) + case ^Type_Cast: + r.type = clone(r.type) + r.expr = clone(r.expr) + case ^Auto_Cast: + r.expr = clone(r.expr) + case ^Inline_Asm_Expr: + r.param_types = clone(r.param_types) + r.return_type = clone(r.return_type) + r.constraints_string = clone(r.constraints_string) + r.asm_string = clone(r.asm_string) - case ^Bad_Stmt: - // empty - case ^Empty_Stmt: - // empty - case ^Expr_Stmt: - r.expr = clone(r.expr) - case ^Tag_Stmt: - r.stmt = clone(r.stmt) + case ^Bad_Stmt: + // empty + case ^Empty_Stmt: + // empty + case ^Expr_Stmt: + r.expr = clone(r.expr) + case ^Tag_Stmt: + r.stmt = clone(r.stmt) - case ^Assign_Stmt: - r.lhs = clone(r.lhs) - r.rhs = clone(r.rhs) - case ^Block_Stmt: - r.label = clone(r.label) - r.stmts = clone(r.stmts) - case ^If_Stmt: - r.label = clone(r.label) - r.init = clone(r.init) - r.cond = clone(r.cond) - r.body = clone(r.body) - r.else_stmt = clone(r.else_stmt) - case ^When_Stmt: - r.cond = clone(r.cond) - r.body = clone(r.body) - r.else_stmt = clone(r.else_stmt) - case ^Return_Stmt: - r.results = clone(r.results) - case ^Defer_Stmt: - r.stmt = clone(r.stmt) - case ^For_Stmt: - r.label = clone(r.label) - r.init = clone(r.init) - r.cond = clone(r.cond) - r.post = clone(r.post) - r.body = clone(r.body) - case ^Range_Stmt: - r.label = clone(r.label) - r.vals = clone(r.vals) - r.expr = clone(r.expr) - r.body = clone(r.body) - case ^Inline_Range_Stmt: - r.label = clone(r.label) - r.val0 = clone(r.val0) - r.val1 = clone(r.val1) - r.expr = clone(r.expr) - r.body = clone(r.body) - case ^Case_Clause: - r.list = clone(r.list) - r.body = clone(r.body) - case ^Switch_Stmt: - r.label = clone(r.label) - r.init = clone(r.init) - r.cond = clone(r.cond) - r.body = clone(r.body) - case ^Type_Switch_Stmt: - r.label = clone(r.label) - r.tag = clone(r.tag) - r.expr = clone(r.expr) - r.body = clone(r.body) - case ^Branch_Stmt: - r.label = auto_cast clone(r.label) - case ^Using_Stmt: - r.list = clone(r.list) - case ^Bad_Decl: - case ^Value_Decl: - r.attributes = clone(r.attributes) - r.names = clone(r.names) - r.type = clone(r.type) - r.values = clone(r.values) - case ^Package_Decl: - case ^Import_Decl: - case ^Foreign_Block_Decl: - r.attributes = clone(r.attributes) - r.foreign_library = clone(r.foreign_library) - r.body = clone(r.body) - case ^Foreign_Import_Decl: - r.name = auto_cast clone(r.name) - case ^Proc_Group: - r.args = clone(r.args) - case ^Attribute: - r.elems = clone(r.elems) - case ^Field: - r.names = clone(r.names) - r.type = clone(r.type) - r.default_value = clone(r.default_value) - case ^Field_List: - r.list = clone(r.list) - case ^Typeid_Type: - r.specialization = clone(r.specialization) - case ^Helper_Type: - r.type = clone(r.type) - case ^Distinct_Type: - r.type = clone(r.type) - case ^Poly_Type: - r.type = auto_cast clone(r.type) - r.specialization = clone(r.specialization) - case ^Proc_Type: - r.params = auto_cast clone(r.params) - r.results = auto_cast clone(r.results) - case ^Pointer_Type: - r.elem = clone(r.elem) - r.tag = clone(r.tag) - case ^Multi_Pointer_Type: - r.elem = clone(r.elem) - case ^Array_Type: - r.len = clone(r.len) - r.elem = clone(r.elem) - case ^Dynamic_Array_Type: - r.elem = clone(r.elem) - case ^Struct_Type: - r.poly_params = auto_cast clone(r.poly_params) - r.align = clone(r.align) - r.fields = auto_cast clone(r.fields) - case ^Union_Type: - r.poly_params = auto_cast clone(r.poly_params) - r.align = clone(r.align) - r.variants = clone(r.variants) - case ^Enum_Type: - r.base_type = clone(r.base_type) - r.fields = clone(r.fields) - case ^Bit_Set_Type: - r.elem = clone(r.elem) - r.underlying = clone(r.underlying) - case ^Map_Type: - r.key = clone(r.key) - r.value = clone(r.value) - case ^Matrix_Type: - r.row_count = clone(r.row_count) - r.column_count = clone(r.column_count) - r.elem = clone(r.elem) - case ^Relative_Type: - r.tag = clone(r.tag) - r.type = clone(r.type) - case: - fmt.panicf("Unhandled node kind: %v", r) + case ^Assign_Stmt: + r.lhs = clone(r.lhs) + r.rhs = clone(r.rhs) + case ^Block_Stmt: + r.label = clone(r.label) + r.stmts = clone(r.stmts) + case ^If_Stmt: + r.label = clone(r.label) + r.init = clone(r.init) + r.cond = clone(r.cond) + r.body = clone(r.body) + r.else_stmt = clone(r.else_stmt) + case ^When_Stmt: + r.cond = clone(r.cond) + r.body = clone(r.body) + r.else_stmt = clone(r.else_stmt) + case ^Return_Stmt: + r.results = clone(r.results) + case ^Defer_Stmt: + r.stmt = clone(r.stmt) + case ^For_Stmt: + r.label = clone(r.label) + r.init = clone(r.init) + r.cond = clone(r.cond) + r.post = clone(r.post) + r.body = clone(r.body) + case ^Range_Stmt: + r.label = clone(r.label) + r.vals = clone(r.vals) + r.expr = clone(r.expr) + r.body = clone(r.body) + case ^Inline_Range_Stmt: + r.label = clone(r.label) + r.val0 = clone(r.val0) + r.val1 = clone(r.val1) + r.expr = clone(r.expr) + r.body = clone(r.body) + case ^Case_Clause: + r.list = clone(r.list) + r.body = clone(r.body) + case ^Switch_Stmt: + r.label = clone(r.label) + r.init = clone(r.init) + r.cond = clone(r.cond) + r.body = clone(r.body) + case ^Type_Switch_Stmt: + r.label = clone(r.label) + r.tag = clone(r.tag) + r.expr = clone(r.expr) + r.body = clone(r.body) + case ^Branch_Stmt: + r.label = auto_cast clone(r.label) + case ^Using_Stmt: + r.list = clone(r.list) + case ^Bad_Decl: + case ^Value_Decl: + r.attributes = clone(r.attributes) + r.names = clone(r.names) + r.type = clone(r.type) + r.values = clone(r.values) + case ^Package_Decl: + case ^Import_Decl: + case ^Foreign_Block_Decl: + r.attributes = clone(r.attributes) + r.foreign_library = clone(r.foreign_library) + r.body = clone(r.body) + case ^Foreign_Import_Decl: + r.name = auto_cast clone(r.name) + case ^Proc_Group: + r.args = clone(r.args) + case ^Attribute: + r.elems = clone(r.elems) + case ^Field: + r.names = clone(r.names) + r.type = clone(r.type) + r.default_value = clone(r.default_value) + case ^Field_List: + r.list = clone(r.list) + case ^Typeid_Type: + r.specialization = clone(r.specialization) + case ^Helper_Type: + r.type = clone(r.type) + case ^Distinct_Type: + r.type = clone(r.type) + case ^Poly_Type: + r.type = auto_cast clone(r.type) + r.specialization = clone(r.specialization) + case ^Proc_Type: + r.params = auto_cast clone(r.params) + r.results = auto_cast clone(r.results) + case ^Pointer_Type: + r.elem = clone(r.elem) + r.tag = clone(r.tag) + case ^Multi_Pointer_Type: + r.elem = clone(r.elem) + case ^Array_Type: + r.len = clone(r.len) + r.elem = clone(r.elem) + case ^Dynamic_Array_Type: + r.elem = clone(r.elem) + case ^Struct_Type: + r.poly_params = auto_cast clone(r.poly_params) + r.align = clone(r.align) + r.fields = auto_cast clone(r.fields) + case ^Union_Type: + r.poly_params = auto_cast clone(r.poly_params) + r.align = clone(r.align) + r.variants = clone(r.variants) + case ^Enum_Type: + r.base_type = clone(r.base_type) + r.fields = clone(r.fields) + case ^Bit_Set_Type: + r.elem = clone(r.elem) + r.underlying = clone(r.underlying) + case ^Map_Type: + r.key = clone(r.key) + r.value = clone(r.value) + case ^Matrix_Type: + r.row_count = clone(r.row_count) + r.column_count = clone(r.column_count) + r.elem = clone(r.elem) + case ^Relative_Type: + r.tag = clone(r.tag) + r.type = clone(r.type) + case: + fmt.panicf("Unhandled node kind: %v", r) + } } return res diff --git a/core/slice/heap/heap.odin b/core/slice/heap/heap.odin index 0a3f53efb..7480a1673 100644 --- a/core/slice/heap/heap.odin +++ b/core/slice/heap/heap.odin @@ -26,7 +26,9 @@ package heap make :: proc(data: []$T, less: proc(a, b: T) -> bool) { // amoritize length lookup length := len(data) - if length <= 1 do return + if length <= 1 { + return + } // start from data parent, no need to consider children for start := (length - 2) / 2; start >= 0; start -= 1 { @@ -53,7 +55,9 @@ push :: proc(data: []$T, less: proc(a, b: T) -> bool) { */ pop :: proc(data: []$T, less: proc(a, b: T) -> bool) { length := len(data) - if length <= 1 do return + if length <= 1 { + return + } last := length @@ -206,7 +210,9 @@ sift_up :: proc(data: []$T, less: proc(a, b: T) -> bool) { // amoritize length lookup length := len(data) - if length <= 1 do return + if length <= 1 { + return + } last := length length = (length - 2) / 2 diff --git a/core/thread/thread.odin b/core/thread/thread.odin index fd8e59a5d..9ba03203f 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -147,7 +147,9 @@ create_and_start :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, } t := create(thread_proc, priority) t.data = rawptr(fn) - if self_cleanup do t.flags += {.Self_Cleanup} + if self_cleanup { + t.flags += {.Self_Cleanup} + } t.init_context = init_context start(t) return t @@ -167,7 +169,9 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co t.data = rawptr(fn) t.user_index = 1 t.user_args = data - if self_cleanup do t.flags += {.Self_Cleanup} + if self_cleanup { + t.flags += {.Self_Cleanup} + } t.init_context = init_context start(t) return t @@ -186,7 +190,9 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex t.user_index = 1 data := data mem.copy(&t.user_args[0], &data, size_of(data)) - if self_cleanup do t.flags += {.Self_Cleanup} + if self_cleanup { + t.flags += {.Self_Cleanup} + } t.init_context = init_context start(t) return t @@ -208,7 +214,9 @@ create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), arg1, arg2 := arg1, arg2 mem.copy(&t.user_args[0], &arg1, size_of(arg1)) mem.copy(&t.user_args[1], &arg2, size_of(arg2)) - if self_cleanup do t.flags += {.Self_Cleanup} + if self_cleanup { + t.flags += {.Self_Cleanup} + } t.init_context = init_context start(t) return t @@ -233,7 +241,9 @@ create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: pr mem.copy(&t.user_args[0], &arg1, size_of(arg1)) mem.copy(&t.user_args[1], &arg2, size_of(arg2)) mem.copy(&t.user_args[2], &arg3, size_of(arg3)) - if self_cleanup do t.flags += {.Self_Cleanup} + if self_cleanup { + t.flags += {.Self_Cleanup} + } t.init_context = init_context start(t) return t @@ -259,7 +269,9 @@ create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: mem.copy(&t.user_args[1], &arg2, size_of(arg2)) mem.copy(&t.user_args[2], &arg3, size_of(arg3)) mem.copy(&t.user_args[3], &arg4, size_of(arg4)) - if self_cleanup do t.flags += {.Self_Cleanup} + if self_cleanup { + t.flags += {.Self_Cleanup} + } t.init_context = init_context start(t) return t From 0ca39c70a51b6f8236c30e010af045303739dbeb Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 11 Nov 2023 13:07:12 +0100 Subject: [PATCH 042/160] Add -microarch:? to help text. --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 59bed1e54..b8abe94f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1876,6 +1876,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Examples:"); print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:native"); + print_usage_line(3, "-microarch:? for a list"); print_usage_line(0, ""); print_usage_line(1, "-reloc-mode:"); From dd9b0ae4e5fd53adc9efc98fcb14aba31521bb66 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 11 Nov 2023 14:06:48 +0100 Subject: [PATCH 043/160] Make pow2_f{16,32,64} contextless for consistency. --- core/math/math.odin | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/math/math.odin b/core/math/math.odin index 0d8873071..dddff4079 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -203,7 +203,8 @@ pow10_f64 :: proc "contextless" (n: f64) -> f64 { return 0 } -pow2_f64 :: proc(#any_int exp: int) -> (res: f64) { +@(require_results) +pow2_f64 :: proc "contextless" (#any_int exp: int) -> (res: f64) { switch { case exp >= -1022 && exp <= 1023: // Normal return transmute(f64)(u64(exp + F64_BIAS) << F64_SHIFT) @@ -221,7 +222,8 @@ pow2_f64 :: proc(#any_int exp: int) -> (res: f64) { unreachable() } -pow2_f32 :: proc(#any_int exp: int) -> (res: f32) { +@(require_results) +pow2_f32 :: proc "contextless" (#any_int exp: int) -> (res: f32) { switch { case exp >= -126 && exp <= 127: // Normal return transmute(f32)(u32(exp + F32_BIAS) << F32_SHIFT) @@ -236,7 +238,8 @@ pow2_f32 :: proc(#any_int exp: int) -> (res: f32) { unreachable() } -pow2_f16 :: proc(#any_int exp: int) -> (res: f16) { +@(require_results) +pow2_f16 :: proc "contextless" (#any_int exp: int) -> (res: f16) { switch { case exp >= -14 && exp <= 15: // Normal return transmute(f16)(u16(exp + F16_BIAS) << F16_SHIFT) From bd190815436f77558740afce2df2eac74da660df Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 12 Nov 2023 01:53:14 +0100 Subject: [PATCH 044/160] fix nil exceptions with incomplete code parse This makes the parser more fault tolerant because the different parse_foo procs return nil when in an invalid state, which is fine most of the time but when creating a node it would crash accessing its position. --- core/odin/ast/clone.odin | 11 +++- core/odin/parser/parser.odin | 98 +++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 79e7a166e..c9bfdfe89 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -7,7 +7,7 @@ import "core:reflect" import "core:odin/tokenizer" _ :: intrinsics -new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { +new_from_positions :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { n, _ := mem.new(T) n.pos = pos n.end = end @@ -23,6 +23,15 @@ new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { return n } +new_from_pos_and_end_node :: proc($T: typeid, pos: tokenizer.Pos, end: ^Node) -> ^T { + return new(T, pos, end != nil ? end.end : {}) +} + +new :: proc { + new_from_positions, + new_from_pos_and_end_node, +} + clone :: proc{ clone_node, clone_expr, diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index bbfaf9114..39bd77055 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -786,8 +786,11 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt { else_stmt = ast.new(ast.Bad_Stmt, p.curr_tok.pos, end_pos(p.curr_tok)) } } - - end := body.end + + end: tokenizer.Pos + if body != nil { + end = body.end + } if else_stmt != nil { end = else_stmt.end } @@ -850,7 +853,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { body = parse_body(p) } - range_stmt := ast.new(ast.Range_Stmt, tok.pos, body.end) + range_stmt := ast.new(ast.Range_Stmt, tok.pos, body) range_stmt.for_pos = tok.pos range_stmt.in_pos = in_tok.pos range_stmt.expr = rhs @@ -910,7 +913,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { rhs = assign_stmt.rhs[0] } - range_stmt := ast.new(ast.Range_Stmt, tok.pos, body.end) + range_stmt := ast.new(ast.Range_Stmt, tok.pos, body) range_stmt.for_pos = tok.pos range_stmt.vals = vals range_stmt.in_pos = assign_stmt.op.pos @@ -920,7 +923,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { } cond_expr := convert_stmt_to_expr(p, cond, "boolean expression") - for_stmt := ast.new(ast.For_Stmt, tok.pos, body.end) + for_stmt := ast.new(ast.For_Stmt, tok.pos, body) for_stmt.for_pos = tok.pos for_stmt.init = init for_stmt.cond = cond_expr @@ -976,7 +979,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { lhs[0] = new_blank_ident(p, tok.pos) rhs[0] = parse_expr(p, true) - as := ast.new(ast.Assign_Stmt, tok.pos, rhs[0].end) + as := ast.new(ast.Assign_Stmt, tok.pos, rhs[0]) as.lhs = lhs as.op = in_tok as.rhs = rhs @@ -1010,14 +1013,14 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { body.stmts = clauses[:] if is_type_switch { - ts := ast.new(ast.Type_Switch_Stmt, tok.pos, body.end) + ts := ast.new(ast.Type_Switch_Stmt, tok.pos, body) ts.tag = tag ts.body = body ts.switch_pos = tok.pos return ts } else { cond := convert_stmt_to_expr(p, tag, "switch expression") - ts := ast.new(ast.Switch_Stmt, tok.pos, body.end) + ts := ast.new(ast.Switch_Stmt, tok.pos, body) ts.init = init ts.cond = cond ts.body = body @@ -1044,7 +1047,7 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: if p.curr_tok.kind == .Eq { eq := expect_token(p, .Eq) value := parse_value(p) - fv := ast.new(ast.Field_Value, elem.pos, value.end) + fv := ast.new(ast.Field_Value, elem.pos, value) fv.field = elem fv.sep = eq.pos fv.value = value @@ -1137,7 +1140,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl body.stmts = decls[:] body.close = close.pos - decl := ast.new(ast.Foreign_Block_Decl, tok.pos, body.end) + decl := ast.new(ast.Foreign_Block_Decl, tok.pos, body) decl.docs = docs decl.tok = tok decl.foreign_library = foreign_library @@ -1248,7 +1251,7 @@ parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast return ast.new(ast.Bad_Stmt, inline_tok.pos, end_pos(p.prev_tok)) } - range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body.end) + range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body) range_stmt.inline_pos = inline_tok.pos range_stmt.for_pos = for_tok.pos range_stmt.val0 = val0 @@ -1304,7 +1307,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { case ^ast.Return_Stmt: error(p, s.pos, "you cannot defer a return statement") } - ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end) + ds := ast.new(ast.Defer_Stmt, tok.pos, stmt) ds.stmt = stmt return ds @@ -1341,8 +1344,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident { label = parse_ident(p) } - end := label.end if label != nil else end_pos(tok) - s := ast.new(ast.Branch_Stmt, tok.pos, end) + s := ast.new(ast.Branch_Stmt, tok.pos, label) s.tok = tok s.label = label expect_semicolon(p, s) @@ -1366,7 +1368,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { if p.curr_tok.kind != .Colon { end := list[len(list)-1] expect_semicolon(p, end) - us := ast.new(ast.Using_Stmt, tok.pos, end.end) + us := ast.new(ast.Using_Stmt, tok.pos, end) us.list = list return us } @@ -1416,13 +1418,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { bd.tok = tok bd.name = name ce := parse_call_expr(p, bd) - es := ast.new(ast.Expr_Stmt, ce.pos, ce.end) + es := ast.new(ast.Expr_Stmt, ce.pos, ce) es.expr = ce return es case "force_inline", "force_no_inline": expr := parse_inlining_operand(p, true, tag) - es := ast.new(ast.Expr_Stmt, expr.pos, expr.end) + es := ast.new(ast.Expr_Stmt, expr.pos, expr) es.expr = expr return es case "unroll": @@ -1444,7 +1446,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag)) case: stmt := parse_stmt(p) - te := ast.new(ast.Tag_Stmt, tok.pos, stmt.pos) + end := stmt.pos if stmt != nil else end_pos(tok) + te := ast.new(ast.Tag_Stmt, tok.pos, end) te.op = tok te.name = name te.stmt = stmt @@ -1572,7 +1575,7 @@ convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt { error(p, stmt.pos, "expected a non-empty statement") } - bs := ast.new(ast.Block_Stmt, stmt.pos, stmt.end) + bs := ast.new(ast.Block_Stmt, stmt.pos, stmt) bs.open = stmt.pos bs.stmts = make([]^ast.Stmt, 1) bs.stmts[0] = stmt @@ -1741,7 +1744,7 @@ parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr { error(p, tok.pos, "variadic field missing type after '..'") type = ast.new(ast.Bad_Expr, tok.pos, end_pos(tok)) } - e := ast.new(ast.Ellipsis, type.pos, type.end) + e := ast.new(ast.Ellipsis, type.pos, type) e.expr = type return e } @@ -1808,7 +1811,7 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr { if is_blank_ident(ident) { error(p, ident.pos, "invalid polymorphic type definition with a blank identifier") } - poly_name := ast.new(ast.Poly_Type, tok.pos, ident.end) + poly_name := ast.new(ast.Poly_Type, tok.pos, ident) poly_name.type = ident append(&list, poly_name) } else { @@ -2154,7 +2157,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ e.inlining = pi case: error(p, tok.pos, "'%s' must be followed by a procedure literal or call", tok.text) - return ast.new(ast.Bad_Expr, tok.pos, expr.end) + return ast.new(ast.Bad_Expr, tok.pos, expr) } return expr } @@ -2204,7 +2207,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { case .Distinct: tok := advance_token(p) type := parse_type(p) - dt := ast.new(ast.Distinct_Type, tok.pos, type.end) + dt := ast.new(ast.Distinct_Type, tok.pos, type) dt.tok = tok.kind dt.type = type return dt @@ -2215,7 +2218,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { switch name.text { case "type": type := parse_type(p) - hp := ast.new(ast.Helper_Type, tok.pos, type.end) + hp := ast.new(ast.Helper_Type, tok.pos, type) hp.tok = tok.kind hp.type = type return hp @@ -2319,7 +2322,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tag_call := parse_call_expr(p, tag) type := parse_type(p) - rt := ast.new(ast.Relative_Type, tok.pos, type.end) + rt := ast.new(ast.Relative_Type, tok.pos, type) rt.tag = tag_call rt.type = type return rt @@ -2328,7 +2331,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return parse_inlining_operand(p, lhs, name) case: expr := parse_expr(p, lhs) - te := ast.new(ast.Tag_Expr, tok.pos, expr.pos) + end := expr.pos if expr != nil else end_pos(tok) + te := ast.new(ast.Tag_Expr, tok.pos, end) te.op = tok te.name = name.text te.expr = expr @@ -2456,7 +2460,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { case .Pointer: tok := expect_token(p, .Pointer) elem := parse_type(p) - ptr := ast.new(ast.Pointer_Type, tok.pos, elem.end) + ptr := ast.new(ast.Pointer_Type, tok.pos, elem) ptr.pointer = tok.pos ptr.elem = elem return ptr @@ -2470,7 +2474,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tok := expect_token(p, .Pointer) close := expect_token(p, .Close_Bracket) elem := parse_type(p) - t := ast.new(ast.Multi_Pointer_Type, open.pos, elem.end) + t := ast.new(ast.Multi_Pointer_Type, open.pos, elem) t.open = open.pos t.pointer = tok.pos t.close = close.pos @@ -2480,7 +2484,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tok := expect_token(p, .Dynamic) close := expect_token(p, .Close_Bracket) elem := parse_type(p) - da := ast.new(ast.Dynamic_Array_Type, open.pos, elem.end) + da := ast.new(ast.Dynamic_Array_Type, open.pos, elem) da.open = open.pos da.dynamic_pos = tok.pos da.close = close.pos @@ -2500,7 +2504,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } close := expect_token(p, .Close_Bracket) elem := parse_type(p) - at := ast.new(ast.Array_Type, open.pos, elem.end) + at := ast.new(ast.Array_Type, open.pos, elem) at.open = open.pos at.len = count at.close = close.pos @@ -2514,7 +2518,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { expect_token(p, .Close_Bracket) value := parse_type(p) - mt := ast.new(ast.Map_Type, tok.pos, value.end) + mt := ast.new(ast.Map_Type, tok.pos, value) mt.tok_pos = tok.pos mt.key = key mt.value = value @@ -2755,7 +2759,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { expect_token(p, .Close_Bracket) elem := parse_type(p) - mt := ast.new(ast.Matrix_Type, tok.pos, elem.end) + mt := ast.new(ast.Matrix_Type, tok.pos, elem) mt.tok_pos = tok.pos mt.row_count = row_count mt.column_count = column_count @@ -2893,7 +2897,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr { eq := expect_token(p, .Eq) value := parse_value(p) - fv := ast.new(ast.Field_Value, elem.pos, value.end) + fv := ast.new(ast.Field_Value, elem.pos, value) fv.field = elem fv.sep = eq.pos fv.value = value @@ -2962,7 +2966,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr { } value := parse_value(p) - fv := ast.new(ast.Field_Value, arg.pos, value.end) + fv := ast.new(ast.Field_Value, arg.pos, value) fv.field = arg fv.sep = eq.pos fv.value = value @@ -2993,7 +2997,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr { o := ast.unparen_expr(operand) if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right { - sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end) + sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce) sce.expr = o sce.call = ce return sce @@ -3101,7 +3105,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a case .Ident: field := parse_ident(p) - sel := ast.new(ast.Selector_Expr, operand.pos, field.end) + sel := ast.new(ast.Selector_Expr, operand.pos, field) sel.expr = operand sel.op = tok sel.field = field @@ -3127,7 +3131,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a type.op = question type.expr = nil - ta := ast.new(ast.Type_Assertion, operand.pos, type.end) + ta := ast.new(ast.Type_Assertion, operand.pos, type) ta.expr = operand ta.type = type @@ -3145,7 +3149,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a case .Ident: field := parse_ident(p) - sel := ast.new(ast.Selector_Expr, operand.pos, field.end) + sel := ast.new(ast.Selector_Expr, operand.pos, field) sel.expr = operand sel.op = tok sel.field = field @@ -3225,7 +3229,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { close := expect_token(p, .Close_Paren) expr := parse_unary_expr(p, lhs) - tc := ast.new(ast.Type_Cast, tok.pos, expr.end) + tc := ast.new(ast.Type_Cast, tok.pos, expr) tc.tok = tok tc.open = open.pos tc.type = type @@ -3237,7 +3241,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { op := advance_token(p) expr := parse_unary_expr(p, lhs) - ac := ast.new(ast.Auto_Cast, op.pos, expr.end) + ac := ast.new(ast.Auto_Cast, op.pos, expr) ac.op = op ac.expr = expr return ac @@ -3247,8 +3251,8 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { .And: op := advance_token(p) expr := parse_unary_expr(p, lhs) - - ue := ast.new(ast.Unary_Expr, op.pos, expr.end) + + ue := ast.new(ast.Unary_Expr, op.pos, expr) ue.op = op ue.expr = expr return ue @@ -3258,7 +3262,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, op.pos, "unary '%s' operator is not supported", op.text) expr := parse_unary_expr(p, lhs) - ue := ast.new(ast.Unary_Expr, op.pos, expr.end) + ue := ast.new(ast.Unary_Expr, op.pos, expr) ue.op = op ue.expr = expr return ue @@ -3266,7 +3270,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { case .Period: op := advance_token(p) field := parse_ident(p) - ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end) + ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field) ise.field = field return ise @@ -3407,7 +3411,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { error(p, p.curr_tok.pos, "no right-hand side in assignment statement") return ast.new(ast.Bad_Stmt, start_tok.pos, end_pos(p.curr_tok)) } - stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1].end) + stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1]) stmt.lhs = lhs stmt.op = op stmt.rhs = rhs @@ -3424,7 +3428,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { rhs := make([]^ast.Expr, 1) rhs[0] = expr - stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1].end) + stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1]) stmt.lhs = lhs stmt.op = op stmt.rhs = rhs @@ -3466,7 +3470,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { error(p, op.pos, "postfix '%s' statement is not supported", op.text) } - es := ast.new(ast.Expr_Stmt, lhs[0].pos, lhs[0].end) + es := ast.new(ast.Expr_Stmt, lhs[0].pos, lhs[0]) es.expr = lhs[0] return es } From cce42f4a6bf45903efa898a9f9c2bc3e5be78601 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sun, 12 Nov 2023 20:48:32 +1100 Subject: [PATCH 045/160] [vendor/x11]: Fix XOpenDisplay --- vendor/x11/xlib/xlib_procs.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index 811ed31ee..86b926ade 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -13,7 +13,7 @@ foreign xlib { // Free data allocated by Xlib XFree :: proc(ptr: rawptr) --- // Opening/closing a display - XOpenDisplay :: proc(display: ^Display, name: cstring) -> ^Display --- + XOpenDisplay :: proc(name: cstring) -> ^Display --- XCloseDisplay :: proc(display: ^Display) --- XSetCloseDownMode :: proc(display: ^Display, mode: CloseMode) --- // Generate a no-op request From 9e35361eb89eeb3e99224d83dfd5bec98d400863 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sun, 12 Nov 2023 20:57:48 +1100 Subject: [PATCH 046/160] [vendor/x11]: Fix definition for EventType --- vendor/x11/xlib/xlib_const.odin | 41 +++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin index b925ec27e..5c3579a8c 100644 --- a/vendor/x11/xlib/xlib_const.odin +++ b/vendor/x11/xlib/xlib_const.odin @@ -68,8 +68,8 @@ BackingStore :: enum i32 { Always = 2, } -EventMask :: bit_set[EventType; int] -EventType :: enum i32 { +EventMask :: bit_set[EventMaskBits; int] +EventMaskBits :: enum i32 { KeyPress = 0, KeyRelease = 1, ButtonPress = 2, @@ -97,6 +97,43 @@ EventType :: enum i32 { OwnerGrabButton = 24, } +EventType :: enum i32 { + KeyPress = 2, + KeyRelease = 3, + ButtonPress = 4, + ButtonRelease = 5, + MotionNotify = 6, + EnterNotify = 7, + LeaveNotify = 8, + FocusIn = 9, + FocusOut = 10, + KeymapNotify = 11, + Expose = 12, + GraphicsExpose = 13, + NoExpose = 14, + VisibilityNotify = 15, + CreateNotify = 16, + DestroyNotify = 17, + UnmapNotify = 18, + MapNotify = 19, + MapRequest = 20, + ReparentNotify = 21, + ConfigureNotify = 22, + ConfigureRequest = 23, + GravityNotify = 24, + ResizeRequest = 25, + CirculateNotify = 26, + CirculateRequest = 27, + PropertyNotify = 28, + SelectionClear = 29, + SelectionRequest = 30, + SelectionNotify = 31, + ColormapNotify = 32, + ClientMessage = 33, + MappingNotify = 34, + GenericEvent = 35, +} + InputMask :: bit_set[InputMaskBits; i32] InputMaskBits :: enum { ShiftMask = 0, From c0bbe1e23d6f966de9fc6d939fd510eb8800f310 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sun, 12 Nov 2023 21:09:41 +1100 Subject: [PATCH 047/160] [vendor/x11]: Add a special type for mouse events --- vendor/x11/xlib/xlib_const.odin | 8 ++++++++ vendor/x11/xlib/xlib_types.odin | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin index 5c3579a8c..a37cee64c 100644 --- a/vendor/x11/xlib/xlib_const.odin +++ b/vendor/x11/xlib/xlib_const.odin @@ -68,6 +68,14 @@ BackingStore :: enum i32 { Always = 2, } +MouseButton :: enum i32 { + Button1 = 1, + Button2 = 2, + Button3 = 3, + Button4 = 4, + Button5 = 5, +} + EventMask :: bit_set[EventMaskBits; int] EventMaskBits :: enum i32 { KeyPress = 0, diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin index bb2f16604..3cee181c8 100644 --- a/vendor/x11/xlib/xlib_types.odin +++ b/vendor/x11/xlib/xlib_types.odin @@ -335,7 +335,7 @@ XButtonEvent :: struct { x_root: i32, y_root: i32, state: InputMask, - button: u32, + button: MouseButton, same_screen: b32, } From 1db95aa09d904a2862d9da22f1efe4862ed7735e Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sun, 12 Nov 2023 21:30:45 +1100 Subject: [PATCH 048/160] [vendor/x11]: Fix XDefaultScreen --- vendor/x11/xlib/xlib_procs.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index 86b926ade..82b32594b 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -44,7 +44,7 @@ foreign xlib { XDefaultDepth :: proc(display: ^Display) -> i32 --- XDefaultGC :: proc(display: ^Display, screen_no: i32) -> GC --- XDefaultRootWindow :: proc(display: ^Display) -> Window --- - XDefaultScreen :: proc(display: ^Display) -> ^Screen --- + XDefaultScreen :: proc(display: ^Display) -> i32 --- XDefaultVisual :: proc(display: ^Display, screen_no: i32) -> ^Visual --- XDefaultScreenOfDisplay :: proc(display: ^Display) -> ^Screen --- From e0ac454ed063b643505b691d2bec1823dbb5c6c8 Mon Sep 17 00:00:00 2001 From: FourteenBrush <74827262+FourteenBrush@users.noreply.github.com> Date: Sun, 12 Nov 2023 17:33:33 +0100 Subject: [PATCH 049/160] Expose strings.ascii_set_* functions --- core/strings/ascii_set.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/strings/ascii_set.odin b/core/strings/ascii_set.odin index 247b38527..98fcd3719 100644 --- a/core/strings/ascii_set.odin +++ b/core/strings/ascii_set.odin @@ -1,4 +1,3 @@ -//+private package strings import "core:unicode/utf8" From 9737c2ad0b6f7737b50f5157d20ec51da1d25d67 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 13 Nov 2023 11:28:39 +1100 Subject: [PATCH 050/160] [examples]: Import x11/xlib instead of x11 --- examples/all/all_vendor.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 76dd9903a..0486bf852 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -46,7 +46,7 @@ import nvg "vendor:nanovg" import nvg_gl "vendor:nanovg/gl" import fontstash "vendor:fontstash" -import x11 "vendor:x11" +import xlib "vendor:x11/xlib" _ :: botan_bindings _ :: botan_blake2b @@ -94,4 +94,4 @@ _ :: nvg _ :: nvg_gl _ :: fontstash -_ :: x11 \ No newline at end of file +_ :: xlib \ No newline at end of file From 55d42492ac31154db9a60a32d361d572c0dfdf2a Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 13 Nov 2023 11:59:36 +1100 Subject: [PATCH 051/160] [vendor/x11]: Add some client to window management communication functions --- vendor/x11/xlib/xlib_const.odin | 54 +++++++++++ vendor/x11/xlib/xlib_procs.odin | 159 ++++++++++++++++++++++++++++++++ vendor/x11/xlib/xlib_types.odin | 8 +- 3 files changed, 217 insertions(+), 4 deletions(-) diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin index a37cee64c..876df9d4b 100644 --- a/vendor/x11/xlib/xlib_const.odin +++ b/vendor/x11/xlib/xlib_const.odin @@ -17,6 +17,18 @@ AllTemporary :: 0 CurrentTime :: 0 NoSymbol :: 0 +XA_WM_CLASS :: Atom(67) +XA_WM_CLIENT_MACHINE :: Atom(36) +XA_WM_COMMAND :: Atom(34) +XA_WM_HINTS :: Atom(35) +XA_WM_ICON_NAME :: Atom(37) +XA_WM_ICON_SIZE :: Atom(38) +XA_WM_NAME :: Atom(39) +XA_WM_NORMAL_HINTS :: Atom(40) +XA_WM_SIZE_HINTS :: Atom(41) +XA_WM_TRANSIENT_FOR :: Atom(68) +XA_WM_ZOOM_HINTS :: Atom(42) + // NOTE(flysand): Some implementations return Status as enum, other return it // as an integer. I will make it a status. Status :: enum i32 { @@ -569,3 +581,45 @@ KeyboardLedMode :: enum i32 { LedModeOff = 0, LedModeOn = 1, } + +WMHints :: bit_set[WMHintsBits; uint] +WMHintsBits :: enum { + InputHint = 0, + StateHint = 1, + IconPixmapHint = 2, + IconWindowHint = 3, + IconPositionHint = 4, + IconMaskHint = 5, + WindowGroupHint = 6, + XUrgencyHint = 8, +} + +WMHintState :: enum i32 { + WithdrawnState = 0, + NormalState = 1, + IconicState = 3, +} + +AllHints :: WMHints{ + .InputHint, + .StateHint, + .IconPixmapHint, + .IconWindowHint, + .IconPositionHint, + .IconMaskHint, + .WindowGroupHint, +} + +SizeHints :: bit_set[SizeHintsBits; uint] +SizeHintsBits :: enum { + USPosition = 0, + USSize = 1, + PPosition = 2, + PSize = 3, + PMinSize = 4, + PMaxSize = 5, + PResizeInc = 6, + PAspect = 7, + PBaseSize = 8, + PWinGravity = 9, +} diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index 82b32594b..d359e48c0 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -1546,4 +1546,163 @@ foreign xlib { XFreeModifiermap :: proc(modmap: ^XModifierKeymap) --- XSetModifierMapping :: proc(display: ^Display, modmap: ^XModifierKeymap) -> i32 --- XGetModifierMapping :: proc(display: ^Display) -> ^XModifierKeymap --- + // Manipulating top-level windows + XIconifyWindow :: proc( + dipslay: ^Display, + window: Window, + screen_no: i32, + ) -> Status --- + XWithdrawWindow :: proc( + dipslay: ^Display, + window: Window, + screen_no: i32, + ) -> Status --- + XReconfigureWMWindow :: proc( + dipslay: ^Display, + window: Window, + screen_no: i32, + mask: WindowChangesMask, + changes: ^XWindowChanges, + ) -> Status --- + // Getting and setting the WM_NAME property + XSetWMName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty + ) --- + XGetWMName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) -> Status --- + XStoreName :: proc( + display: ^Display, + window: Window, + name: cstring + ) --- + XFetchName :: proc( + display: ^Display, + window: Window, + name: ^cstring + ) -> Status --- + XSetWMIconName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty + ) --- + XGetWMIconName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) -> Status --- + XSetIconName :: proc( + display: ^Display, + window: Window, + name: cstring, + ) --- + XGetIconName :: proc( + display: ^Display, + window: Window, + prop: ^cstring, + ) -> Status --- + // Setting and reading WM_HINTS property + XAllocWMHints :: proc() -> ^XWMHints --- + XSetWMHints :: proc( + display: ^Display, + window: Window, + hints: ^XWMHints, + ) --- + XGetWMHints :: proc( + display: ^Display, + window: Window, + ) -> ^XWMHints --- + // Setting and reading MW_NORMAL_HINTS property + XAllocSizeHints :: proc() -> ^XSizeHints --- + XSetWMNormalHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + ) --- + XGetWMNormalHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + flags: ^SizeHints, + ) -> Status --- + XSetWMSizeHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + prop: Atom, + ) --- + XGetWMSizeHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + masks: ^SizeHints, + prop: Atom, + ) -> Status --- + // Setting and reading the WM_CLASS property + XAllocClassHint :: proc() -> ^XClassHint --- + XSetClassHint :: proc( + display: ^Display, + window: Window, + hint: ^XClassHint, + ) --- + XGetClassHint :: proc( + display: ^Display, + window: Window, + hint: ^XClassHint, + ) -> Status --- + // Setting and reading WM_TRANSIENT_FOR property + XSetTransientForHint :: proc( + display: ^Display, + window: Window, + prop_window: Window, + ) --- + XGetTransientForHint :: proc( + display: ^Display, + window: Window, + prop_window: ^Window, + ) -> Status --- + // Setting and reading the WM_PROTOCOLS property + XSetWMProtocols :: proc( + display: ^Display, + window: Window, + protocols: [^]Atom, + count: i32, + ) -> Status --- + XGetWMProtocols :: proc( + display: ^Display, + window: Window, + protocols: ^[^]Atom, + count: ^i32 + ) -> Status --- + // Setting and reading the WM_COLORMAP_WINDOWS property + XSetWMColormapWindows :: proc( + display: ^Display, + window: Window, + colormap_windows: [^]Window, + count: i32, + ) -> Status --- + XGetWMColormapWindows :: proc( + display: ^Display, + window: Window, + colormap_windows: ^[^]Window, + count: ^i32, + ) -> Status --- + // Setting and reading the WM_ICON_SIZE_PROPERTY + XAllocIconSize :: proc() -> ^XIconSize --- + XSetIconSizes :: proc( + display: ^Display, + window: Window, + size_list: [^]XIconSize, + count: i32, + ) --- + XGetIconSizes :: proc( + display: ^Display, + window: Window, + size_list: ^[^]XIconSize, + count: ^i32, + ) -> Status --- } diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin index 3cee181c8..9122341f3 100644 --- a/vendor/x11/xlib/xlib_types.odin +++ b/vendor/x11/xlib/xlib_types.odin @@ -1162,7 +1162,7 @@ XcmsFunctionSet :: struct { /* ---- X11/Xutil.h --------------------------------------------------------*/ XSizeHints :: struct { - flags: int, + flags: SizeHints, x: i32, y: i32, width: i32, @@ -1181,9 +1181,9 @@ XSizeHints :: struct { } XWMHints :: struct { - flags: int, - input: i32, - initial_state: i32, + flags: WMHints, + input: b32, + initial_state: WMHintState, icon_pixmap: Pixmap, icon_window: Window, icon_x: i32, From 79d3c3be6685105a9912520b11f57f26578131fe Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 13 Nov 2023 19:40:06 +1100 Subject: [PATCH 052/160] [vendor/x11]: Add xlib utility functions, make compileable with -strict-style --- vendor/x11/xlib/xlib_const.odin | 26 ++ vendor/x11/xlib/xlib_procs.odin | 594 +++++++++++++++++++++----------- vendor/x11/xlib/xlib_types.odin | 2 +- 3 files changed, 424 insertions(+), 198 deletions(-) diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin index 876df9d4b..87b13479e 100644 --- a/vendor/x11/xlib/xlib_const.odin +++ b/vendor/x11/xlib/xlib_const.odin @@ -623,3 +623,29 @@ SizeHintsBits :: enum { PBaseSize = 8, PWinGravity = 9, } + +VisualInfoMask :: bit_set[VisualInfoMaskBits; int] +VisualInfoMaskBits :: enum { + VisualIDMask = 0, + VisualScreenMask = 1, + VisualDepthMask = 2, + VisualClassMask = 3, + VisualRedMaskMask = 4, + VisualGreenMaskMask = 5, + VisualBlueMaskMask = 6, + VisualColormapSizeMask = 7, + VisualBitsPerRGBMask = 8, +} + +VisualNoMask :: VisualInfoMask {} +VisualAllMask :: VisualInfoMask { + .VisualIDMask, + .VisualScreenMask, + .VisualDepthMask, + .VisualClassMask, + .VisualRedMaskMask, + .VisualGreenMaskMask, + .VisualBlueMaskMask, + .VisualColormapSizeMask, + .VisualBitsPerRGBMask, +} diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index d359e48c0..dc2141624 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -90,21 +90,21 @@ foreign xlib { XAddConnectionWatch :: proc( display: ^Display, procedure: XConnectionWatchProc, - data: rawptr + data: rawptr, ) -> Status --- XRemoveConnectionWatch :: proc( display: ^Display, procedure: XConnectionWatchProc, - data: rawptr + data: rawptr, ) -> Status --- XProcessInternalConnections :: proc( display: ^Display, - fd: i32 + fd: i32, ) --- XInternalConnectionNumbers :: proc( display: ^Display, fds: ^[^]i32, - count: ^i32 + count: ^i32, ) -> Status --- // Windows functions XVisualIDFromVisual :: proc(visual: ^Visual) -> VisualID --- @@ -121,7 +121,7 @@ foreign xlib { class: WindowClass, visual: ^Visual, attr_mask: WindowAttributeMask, - attr: ^XSetWindowAttributes + attr: ^XSetWindowAttributes, ) -> Window --- XCreateSimpleWindow :: proc( display: ^Display, @@ -132,7 +132,7 @@ foreign xlib { height: u32, bordersz: u32, border: int, - bg: int + bg: int, ) -> Window --- XDestroyWindow :: proc(display: ^Display, window: Window) --- XDestroySubwindows :: proc(display: ^Display, window: Window) --- @@ -147,19 +147,19 @@ foreign xlib { display: ^Display, window: Window, mask: WindowChangesMask, - values: XWindowChanges + values: XWindowChanges, ) --- XMoveWindow :: proc( display: ^Display, window: Window, x: i32, - y: i32 + y: i32, ) --- XResizeWindow :: proc( display: ^Display, window: Window, width: u32, - height: u32 + height: u32, ) --- XMoveResizeWindow :: proc( display: ^Display, @@ -167,12 +167,12 @@ foreign xlib { x: i32, y: i32, width: u32, - height: u32 + height: u32, ) --- XSetWindowBorderWidth :: proc( display: ^Display, window: Window, - width: u32 + width: u32, ) --- // Window: changing stacking order XRaiseWindow :: proc(display: ^Display, window: Window) --- @@ -186,31 +186,31 @@ foreign xlib { display: ^Display, window: Window, attr_mask: WindowAttributeMask, - attr: XWindowAttributes + attr: XWindowAttributes, ) --- XSetWindowBackground :: proc( display: ^Display, window: Window, - pixel: uint + pixel: uint, ) --- XSetWindowBackgroundMap :: proc( display: ^Display, window: Window, - pixmap: Pixmap + pixmap: Pixmap, ) --- XSetWindowColormap :: proc( display: ^Display, window: Window, - colormap: Colormap + colormap: Colormap, ) --- XDefineCursor :: proc( display: ^Display, window: Window, - cursor: Cursor + cursor: Cursor, ) --- XUndefineCursor :: proc( display: ^Display, - window: Window + window: Window, ) --- // Windows: querying information XQueryTree :: proc( @@ -219,12 +219,12 @@ foreign xlib { root: ^Window, parent: ^Window, children: ^[^]Window, - nchildren: ^u32 + nchildren: ^u32, ) -> Status --- XGetWindowAttributes :: proc( display: ^Display, window: Window, - attr: XWindowAttributes + attr: XWindowAttributes, ) --- XGetGeometry :: proc( display: ^Display, @@ -235,7 +235,7 @@ foreign xlib { width: ^u32, height: ^u32, border_sz: ^u32, - depth: ^u32 + depth: ^u32, ) -> Status --- // Windows: translating screen coordinates XTranslateCoordinates :: proc( @@ -245,7 +245,7 @@ foreign xlib { src_x: i32, src_y: i32, dst_x: ^i32, - dst_y: ^i32 + dst_y: ^i32, ) -> b32 --- XQueryPointer :: proc( display: ^Display, @@ -255,29 +255,29 @@ foreign xlib { root_y: ^i32, x: ^i32, y: ^i32, - mask: ^KeyMask + mask: ^KeyMask, ) -> b32 --- // Atoms XInternAtom :: proc( display: ^Display, name: cstring, - existing: b32 + existing: b32, ) -> Atom --- XInternAtoms :: proc( display: ^Display, names: [^]cstring, count: i32, - atoms: [^]Atom + atoms: [^]Atom, ) -> Status --- XGetAtomName :: proc( display: ^Display, - atom: Atom + atom: Atom, ) -> cstring --- XGetAtomNames :: proc( display: ^Display, atoms: [^]Atom, count: i32, - names: [^]cstring + names: [^]cstring, ) -> Status --- // Windows: Obtaining and changing properties XGetWindowProperty :: proc( @@ -292,12 +292,12 @@ foreign xlib { act_format: [^]i32, nitems: [^]uint, bytes_after: [^]uint, - props: ^rawptr + props: ^rawptr, ) -> i32 --- XListProperties :: proc( display: ^Display, window: Window, - num: ^i32 + num: ^i32, ) -> [^]Atom --- XChangeProperty :: proc( display: ^Display, @@ -307,30 +307,30 @@ foreign xlib { format: i32, mode: i32, data: rawptr, - count: i32 + count: i32, ) --- XRotateWindowProperties :: proc( display: ^Display, window: Window, props: [^]Atom, nprops: i32, - npos: i32 + npos: i32, ) --- XDeleteProperty :: proc( display: ^Display, window: Window, - prop: Atom + prop: Atom, ) --- // Selections XSetSelectionOwner :: proc( display: ^Display, selection: Atom, owber: Window, - time: Time + time: Time, ) --- XGetSelectionOwner :: proc( display: ^Display, - selection: Atom + selection: Atom, ) -> Window --- XConvertSelection :: proc( display: ^Display, @@ -338,7 +338,7 @@ foreign xlib { target: Atom, property: Atom, requestor: Window, - time: Time + time: Time, ) --- // Creating and freeing pixmaps XCreatePixmap :: proc( @@ -346,16 +346,16 @@ foreign xlib { drawable: Drawable, width: u32, height: u32, - depth: u32 + depth: u32, ) -> Pixmap --- XFreePixmap :: proc( display: ^Display, - pixmap: Pixmap + pixmap: Pixmap, ) --- // Creating recoloring and freeing cursors XCreateFontCursor :: proc( display: ^Display, - shape: CursorShape + shape: CursorShape, ) -> Cursor --- XCreateGlyphCursor :: proc( display: ^Display, @@ -364,7 +364,7 @@ foreign xlib { src_char: u32, mask_char: u32, fg: ^XColor, - bg: ^XColor + bg: ^XColor, ) -> Cursor --- XCreatePixmapCursor :: proc( display: ^Display, @@ -373,7 +373,7 @@ foreign xlib { fg: XColor, bg: ^XColor, x: u32, - y: u32 + y: u32, ) -> Cursor --- XQueryBestCursor :: proc( display: ^Display, @@ -381,13 +381,13 @@ foreign xlib { width: u32, height: u32, out_width: ^u32, - out_height: ^u32 + out_height: ^u32, ) -> Status --- XRecolorCursor :: proc( display: ^Display, cursor: Cursor, fg: ^XColor, - bg: ^XColor + bg: ^XColor, ) --- XFreeCursor :: proc(display: ^Display, cursor: Cursor) --- // Creation/destruction of colormaps @@ -395,15 +395,15 @@ foreign xlib { display: ^Display, window: Window, visual: Visual, - alloc: ColormapAlloc + alloc: ColormapAlloc, ) -> Colormap --- XCopyColormapAndFree :: proc( display: ^Display, - colormap: Colormap + colormap: Colormap, ) -> Colormap --- XFreeColormap :: proc( display: ^Display, - colormap: Colormap + colormap: Colormap, ) --- // Mapping color names to values XLookupColor :: proc( @@ -411,7 +411,7 @@ foreign xlib { colomap: Colormap, name: cstring, exact: ^XColor, - screen: ^XColor + screen: ^XColor, ) -> Status --- XcmsLookupColor :: proc( display: ^Display, @@ -419,26 +419,26 @@ foreign xlib { name: cstring, exact: XcmsColor, screen: XcmsColor, - format: XcmsColorFormat + format: XcmsColorFormat, ) -> Status --- // Allocating and freeing color cells XAllocColor :: proc( display: ^Display, colormap: Colormap, - screen: ^XColor + screen: ^XColor, ) -> Status --- XcmsAllocColor :: proc( display: ^Display, colormap: Colormap, color: ^XcmsColor, - format: XcmsColorFormat + format: XcmsColorFormat, ) -> Status --- XAllocNamedColor :: proc( display: ^Display, colormap: Colormap, name: cstring, screen: ^XColor, - exact: ^XColor + exact: ^XColor, ) -> Status --- XcmsAllocNamedColor :: proc( display: ^Display, @@ -446,7 +446,7 @@ foreign xlib { name: cstring, screen: ^XcmsColor, exact: ^XcmsColor, - format: XcmsColorFormat + format: XcmsColorFormat, ) -> Status --- XAllocColorCells :: proc( display: ^Display, @@ -455,7 +455,7 @@ foreign xlib { pmasks: [^]uint, np: u32, pixels: [^]uint, - npixels: u32 + npixels: u32, ) -> Status --- XAllocColorPlanes :: proc( display: ^Display, @@ -468,74 +468,74 @@ foreign xlib { nblues: i32, rmask: [^]uint, gmask: [^]uint, - bmask: [^]uint + bmask: [^]uint, ) -> Status --- XFreeColors :: proc( display: ^Display, colormap: Colormap, pixels: [^]uint, npixels: i32, - planes: uint + planes: uint, ) --- // Modifying and querying colormap cells XStoreColor :: proc( display: ^Display, colormap: Colormap, - color: ^XColor + color: ^XColor, ) --- XStoreColors :: proc( display: ^Display, colormap: Colormap, color: [^]XColor, - ncolors: i32 + ncolors: i32, ) --- XcmsStoreColor :: proc( display: ^Display, colormap: Colormap, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsStoreColors :: proc( display: ^Display, colormap: Colormap, colors: [^]XcmsColor, ncolors: XcmsColor, - cflags: [^]b32 + cflags: [^]b32, ) -> Status --- XStoreNamedColor :: proc( display: ^Display, colormap: Colormap, name: cstring, pixel: uint, - flags: ColorFlags + flags: ColorFlags, ) --- XQueryColor :: proc( display: ^Display, colormap: Colormap, - color: ^XColor + color: ^XColor, ) --- XQueryColors :: proc( display: ^Display, colormap: Colormap, colors: [^]XColor, - ncolors: i32 + ncolors: i32, ) --- XcmsQueryColor :: proc( display: ^Display, colormap: Colormap, color: ^XcmsColor, - format: XcmsColorFormat + format: XcmsColorFormat, ) -> Status --- XcmsQueryColors :: proc( display: ^Display, colormap: Colormap, color: [^]XcmsColor, ncolors: i32, - format: XcmsColorFormat + format: XcmsColorFormat, ) -> Status --- // Getting and setting the color conversion context (CCC) of a colormap XcmsCCCOfColormap :: proc( display: ^Display, - colormap: Colormap + colormap: Colormap, ) -> XcmsCCC --- XcmsSetCCCOfColormap :: proc( display: ^Display, @@ -554,17 +554,17 @@ foreign xlib { // Modifying the attributes of color conversion context XcmsSetWhitePoint :: proc( ccc: XcmsCCC, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsSetCompressionProc :: proc( ccc: XcmsCCC, cproc: XcmsCompressionProc, - data: rawptr + data: rawptr, ) -> XcmsCompressionProc --- XcmsSetWhiteAdjustProc :: proc( ccc: XcmsCCC, aproc: XcmsWhiteAdjustProc, - data: rawptr + data: rawptr, ) -> XcmsWhiteAdjustProc --- // Creating and freeing the color conversion context XcmsCreateCCC :: proc( @@ -575,7 +575,7 @@ foreign xlib { cproc: XcmsCompressionProc, cdata: rawptr, aproc: XcmsWhiteAdjustProc, - adata: rawptr + adata: rawptr, ) -> XcmsCCC --- XcmsFreeCCC :: proc(ccc: XcmsCCC) --- // Converting between colorspaces @@ -584,7 +584,7 @@ foreign xlib { colors: [^]XcmsColor, ncolors: u32, format: XcmsColorFormat, - cflags: [^]b32 + cflags: [^]b32, ) -> Status --- // Pre-defined gamut compression callbacks XcmsCIELabClipL :: proc( @@ -592,63 +592,63 @@ foreign xlib { colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsCIELabClipab :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsCIELabClipLab :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsCIELuvClipL :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsCIELuvClipuv :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsCIELuvClipLuv :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsTekHVCClipV :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsTekHVCClipC :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- XcmsTekHVCClipVC :: proc( ctx: XcmsCCC, colors: [^]XcmsColor, ncolors: u32, index: u32, - flags: [^]b32 + flags: [^]b32, ) -> Status --- // Pre-defined white-point adjustment procedures XcmsCIELabWhiteShiftColors :: proc( @@ -658,7 +658,7 @@ foreign xlib { target_format: XcmsColorFormat, colors: [^]XcmsColor, ncolors: u32, - compression: [^]b32 + compression: [^]b32, ) -> Status --- XcmsCIELuvWhiteShiftColors :: proc( ctx: XcmsCCC, @@ -667,7 +667,7 @@ foreign xlib { target_format: XcmsColorFormat, colors: [^]XcmsColor, ncolors: u32, - compression: [^]b32 + compression: [^]b32, ) -> Status --- XcmsTekHVCWhiteShiftColors :: proc( ctx: XcmsCCC, @@ -676,136 +676,136 @@ foreign xlib { target_format: XcmsColorFormat, colors: [^]XcmsColor, ncolors: u32, - compression: [^]b32 + compression: [^]b32, ) -> Status --- // Color querying XcmsQueryBlack :: proc( ccc: XcmsCCC, format: XcmsColorFormat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsQueryBlue :: proc( ccc: XcmsCCC, format: XcmsColorFormat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsQueryGreen :: proc( ccc: XcmsCCC, format: XcmsColorFormat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsQueryRed :: proc( ccc: XcmsCCC, format: XcmsColorFormat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsQueryWhite :: proc( ccc: XcmsCCC, format: XcmsColorFormat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- // CIELab queries XcmsCIELabQueryMaxC :: proc( ccc: XcmsCCC, hue: XcmsFloat, lstar: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsCIELabQueryMaxL :: proc( ccc: XcmsCCC, hue: XcmsFloat, chroma: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsCIELabQueryMaxLC :: proc( ccc: XcmsCCC, hue: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsCIELabQueryMinL :: proc( ccc: XcmsCCC, hue: XcmsFloat, chroma: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- // CIEluv queries XcmsCIELuvQueryMaxC :: proc( ccc: XcmsCCC, hue: XcmsFloat, lstar: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsCIELuvQueryMaxL :: proc( ccc: XcmsCCC, hue: XcmsFloat, chroma: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsCIELuvQueryMaxLC :: proc( ccc: XcmsCCC, hue: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsCIELuvQueryMinL :: proc( ccc: XcmsCCC, hue: XcmsFloat, chroma: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- // TexHVX queries XcmsTekHVCQueryMaxC :: proc( ccc: XcmsCCC, hue: XcmsFloat, value: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsTekHVCQueryMaxV :: proc( ccc: XcmsCCC, hue: XcmsFloat, chroma: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsTekHVCQueryMaxVC :: proc( ccc: XcmsCCC, hue: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- XcmsTekHVCQueryMaxVSamples :: proc( ccc: XcmsCCC, hue: XcmsFloat, colors: [^]XcmsColor, - nsamples: u32 + nsamples: u32, ) -> Status --- XcmsTekHVCQueryMinV :: proc( ccc: XcmsCCC, hue: XcmsFloat, chroma: XcmsFloat, - color: ^XcmsColor + color: ^XcmsColor, ) -> Status --- // Graphics context functions XCreateGC :: proc( display: ^Display, drawable: Drawable, mask: GCAttributeMask, - attr: ^XGCValues + attr: ^XGCValues, ) -> GC --- XCopyGC :: proc( display: ^Display, src: GC, dst: GC, - mask: GCAttributeMask + mask: GCAttributeMask, ) --- XChangeGC :: proc( display: ^Display, gc: GC, mask: GCAttributeMask, - values: ^XGCValues + values: ^XGCValues, ) --- XGetGCValues :: proc( display: ^Display, gc: GC, mask: GCAttributeMask, - values: ^XGCValues + values: ^XGCValues, ) -> Status --- XFreeGC :: proc(display: ^Display, gc: GC) --- XGCContextFromGC :: proc(gc: GC) -> GContext --- @@ -817,27 +817,27 @@ foreign xlib { fg: uint, bg: uint, fn: GCFunction, - pmask: uint + pmask: uint, ) --- XSetForeground :: proc( display: ^Display, gc: GC, - fg: uint + fg: uint, ) --- XSetBackground :: proc( display: ^Display, gc: GC, - bg: uint + bg: uint, ) --- XSetFunction :: proc( display: ^Display, gc: GC, - fn: GCFunction + fn: GCFunction, ) --- XSetPlaneMask :: proc( display: ^Display, gc: GC, - pmask: uint + pmask: uint, ) --- XSetLineAttributes :: proc( display: ^Display, @@ -845,24 +845,24 @@ foreign xlib { width: u32, line_style: LineStyle, cap_style: CapStyle, - join_style: JoinStyle + join_style: JoinStyle, ) --- XSetDashes :: proc( display: ^Display, gc: GC, dash_offs: i32, dash_list: [^]i8, - n: i32 + n: i32, ) --- XSetFillStyle :: proc( display: ^Display, gc: GC, - style: FillStyle + style: FillStyle, ) --- XSetFillRule :: proc( display: ^Display, gc: GC, - rule: FillRule + rule: FillRule, ) --- XQueryBestSize :: proc( display: ^Display, @@ -871,7 +871,7 @@ foreign xlib { width: u32, height: u32, out_width: ^u32, - out_height: ^u32 + out_height: ^u32, ) -> Status --- XQueryBestTile :: proc( display: ^Display, @@ -879,7 +879,7 @@ foreign xlib { width: u32, height: u32, out_width: ^u32, - out_height: ^u32 + out_height: ^u32, ) -> Status --- XQueryBestStripple :: proc( display: ^Display, @@ -887,7 +887,7 @@ foreign xlib { width: u32, height: u32, out_width: u32, - out_height: u32 + out_height: u32, ) -> Status --- XSetTile :: proc(display: ^Display, gc: GC, tile: Pixmap) --- XSetStripple :: proc(display: ^Display, gc: GC, stripple: Pixmap) --- @@ -902,7 +902,7 @@ foreign xlib { y: i32, rects: [^]XRectangle, n: i32, - ordering: i32 + ordering: i32, ) --- XSetArcMode :: proc(display: ^Display, gc: GC, mode: ArcMode) --- XSetSubwindowMode :: proc(display: ^Display, gc: GC, mode: SubwindowMode) --- @@ -915,11 +915,11 @@ foreign xlib { y: i32, width: u32, height: u32, - exp: b32 + exp: b32, ) --- XClearWindow :: proc( display: ^Display, - window: Window + window: Window, ) --- XCopyArea :: proc( display: ^Display, @@ -931,7 +931,7 @@ foreign xlib { width: u32, height: u32, dst_x: i32, - dst_y: i32 + dst_y: i32, ) --- XCopyPlane :: proc( display: ^Display, @@ -944,7 +944,7 @@ foreign xlib { height: u32, dst_x: i32, dst_y: i32, - plane: uint + plane: uint, ) --- // Drawing lines, points, rectangles and arc XDrawPoint :: proc( @@ -952,7 +952,7 @@ foreign xlib { drawable: Drawable, gc: GC, x: i32, - y: i32 + y: i32, ) --- XDrawPoints :: proc( display: Display, @@ -960,7 +960,7 @@ foreign xlib { gc: GC, point: [^]XPoint, npoints: i32, - mode: CoordMode + mode: CoordMode, ) --- XDrawLine :: proc( display: ^Display, @@ -969,21 +969,21 @@ foreign xlib { x1: i32, y1: i32, x2: i32, - y2: i32 + y2: i32, ) --- XDrawLines :: proc( display: ^Display, drawable: Drawable, gc: GC, points: [^]XPoint, - npoints: i32 + npoints: i32, ) --- XDrawSegments :: proc( display: ^Display, drawable: Drawable, gc: GC, segs: [^]XSegment, - nsegs: i32 + nsegs: i32, ) --- XDrawRectangle :: proc( display: ^Display, @@ -992,14 +992,14 @@ foreign xlib { x: i32, y: i32, width: u32, - height: u32 + height: u32, ) --- XDrawRectangles :: proc( display: ^Display, drawable: Drawable, gc: GC, rects: [^]XRectangle, - nrects: i32 + nrects: i32, ) --- XDrawArc :: proc( display: ^Display, @@ -1010,14 +1010,14 @@ foreign xlib { width: u32, height: u32, angle1: i32, - angle2: i32 + angle2: i32, ) --- XDrawArcs :: proc( display: ^Display, drawable: Drawable, gc: GC, arcs: [^]XArc, - narcs: i32 + narcs: i32, ) --- // Filling areas XFillRectangle :: proc( @@ -1027,14 +1027,14 @@ foreign xlib { x: i32, y: i32, width: u32, - height: u32 + height: u32, ) --- XFillRectangles :: proc( display: ^Display, drawable: Drawable, gc: GC, rects: [^]XRectangle, - nrects: i32 + nrects: i32, ) --- XFillPolygon :: proc( display: ^Display, @@ -1043,7 +1043,7 @@ foreign xlib { points: [^]XPoint, npoints: i32, shape: Shape, - mode: CoordMode + mode: CoordMode, ) --- XFillArc :: proc( display: ^Display, @@ -1054,14 +1054,14 @@ foreign xlib { width: u32, height: u32, angle1: i32, - angle2: i32 + angle2: i32, ) --- XFillArcs :: proc( display: ^Display, drawable: Drawable, gc: GC, arcs: [^]XArc, - narcs: i32 + narcs: i32, ) --- // Font metrics XLoadFont :: proc(display: ^Display, name: cstring) -> Font --- @@ -1077,7 +1077,7 @@ foreign xlib { pat: cstring, max: i32, count: ^i32, - info: ^[^]XFontStruct + info: ^[^]XFontStruct, ) -> [^]cstring --- XFreeFontInfo :: proc(names: [^]cstring, info: [^]XFontStruct, count: i32) --- // Computing character string sizes @@ -1090,7 +1090,7 @@ foreign xlib { direction: ^FontDirection, ascent: ^i32, descent: ^i32, - ret: ^XCharStruct + ret: ^XCharStruct, ) --- XTextExtents16 :: proc( font_struct: ^XFontStruct, @@ -1099,7 +1099,7 @@ foreign xlib { direction: ^FontDirection, ascent: ^i32, descent: ^i32, - ret: ^XCharStruct + ret: ^XCharStruct, ) --- XQueryTextExtents :: proc( display: ^Display, @@ -1109,7 +1109,7 @@ foreign xlib { direction: ^FontDirection, ascent: ^i32, descent: ^i32, - ret: ^XCharStruct + ret: ^XCharStruct, ) --- XQueryTextExtents16 :: proc( display: ^Display, @@ -1119,7 +1119,7 @@ foreign xlib { direction: ^FontDirection, ascent: ^i32, descent: ^i32, - ret: ^XCharStruct + ret: ^XCharStruct, ) --- // Drawing complex text XDrawText :: proc( @@ -1129,7 +1129,7 @@ foreign xlib { x: i32, y: i32, items: XTextItem, - nitems: i32 + nitems: i32, ) --- XDrawText16 :: proc( display: ^Display, @@ -1138,7 +1138,7 @@ foreign xlib { x: i32, y: i32, items: XTextItem16, - nitems: i32 + nitems: i32, ) --- // Drawing text characters XDrawString :: proc( @@ -1148,7 +1148,7 @@ foreign xlib { x: i32, y: i32, string: [^]u8, - length: i32 + length: i32, ) --- XDrawString16 :: proc( display: ^Display, @@ -1157,7 +1157,7 @@ foreign xlib { x: i32, y: i32, string: [^]XChar2b, - length: i32 + length: i32, ) --- XDrawImageString :: proc( display: ^Display, @@ -1166,7 +1166,7 @@ foreign xlib { x: i32, y: i32, string: [^]u8, - length: i32 + length: i32, ) --- XDrawImageString16 :: proc( display: ^Display, @@ -1175,7 +1175,7 @@ foreign xlib { x: i32, y: i32, string: [^]XChar2b, - length: i32 + length: i32, ) --- // Transferring images between client and server XInitImage :: proc(image: ^XImage) -> Status --- @@ -1189,7 +1189,7 @@ foreign xlib { dst_x: i32, dst_y: i32, width: u32, - height: u32 + height: u32, ) --- XGetImage :: proc( display: ^Display, @@ -1199,7 +1199,7 @@ foreign xlib { width: u32, height: u32, mask: uint, - format: ImageFormat + format: ImageFormat, ) -> ^XImage --- XGetSubImage :: proc( display: ^Display, @@ -1212,7 +1212,7 @@ foreign xlib { format: ImageFormat, dst: ^XImage, dst_x: i32, - dst_y: i32 + dst_y: i32, ) -> ^XImage --- // Window and session manager functions XReparentWindow :: proc( @@ -1220,20 +1220,20 @@ foreign xlib { window: Window, parent: Window, x: i32, - y: i32 + y: i32, ) --- XChangeSaveSet :: proc( display: ^Display, window: Window, - mode: SaveSetChangeMode + mode: SaveSetChangeMode, ) --- XAddToSaveSet :: proc( display: ^Display, - window: Window + window: Window, ) --- XRemoveFromSaveSet :: proc( display: ^Display, - window: Window + window: Window, ) --- // Managing installed colormaps XInstallColormap :: proc(display: ^Display, colormap: Colormap) --- @@ -1254,7 +1254,7 @@ foreign xlib { timeout: i32, interval: i32, blanking: ScreenSaverBlanking, - exposures: ScreenSavingExposures + exposures: ScreenSavingExposures, ) --- XForceScreenSaver :: proc(display: ^Display, mode: ScreenSaverForceMode) --- XActivateScreenSaver :: proc(display: ^Display) --- @@ -1264,7 +1264,7 @@ foreign xlib { timeout: ^i32, interval: ^i32, blanking: ^ScreenSaverBlanking, - exposures: ^ScreenSavingExposures + exposures: ^ScreenSavingExposures, ) --- // Controlling host address XAddHost :: proc(display: ^Display, addr: ^XHostAddress) --- @@ -1289,58 +1289,58 @@ foreign xlib { display: ^Display, event: ^XEvent, predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, - ctx: rawptr + ctx: rawptr, ) --- XCheckIfEvent :: proc( display: ^Display, event: ^XEvent, predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, - arg: rawptr + arg: rawptr, ) -> b32 --- XPeekIfEvent :: proc( display: ^Display, event: ^XEvent, predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, - ctx: rawptr + ctx: rawptr, ) --- // Selecting events using a window or event mask XWindowEvent :: proc( display: ^Display, window: Window, mask: EventMask, - event: ^XEvent + event: ^XEvent, ) --- XCheckWindowEvent :: proc( display: ^Display, window: Window, mask: EventMask, - event: ^XEvent + event: ^XEvent, ) -> b32 --- XMaskEvent :: proc( display: ^Display, mask: EventMask, - event: ^XEvent + event: ^XEvent, ) --- XCheckMaskEvent :: proc( display: ^Display, mask: EventMask, - event: ^XEvent + event: ^XEvent, ) -> b32 --- XCheckTypedEvent :: proc( display: ^Display, type: EventType, - event: ^XEvent + event: ^XEvent, ) -> b32 --- XCheckTypedWindowEvent :: proc( display: ^Display, window: Window, type: EventType, - event: ^XEvent + event: ^XEvent, ) -> b32 --- // Putting events back XPutBackEvent :: proc( display: ^Display, - event: ^XEvent + event: ^XEvent, ) --- // Sending events to other applications XSendEvent :: proc( @@ -1348,7 +1348,7 @@ foreign xlib { window: Window, propagate: b32, mask: EventMask, - event: ^XEvent + event: ^XEvent, ) -> Status --- // Getting the history of pointer motion XDisplayMotionBufferSize :: proc(display: ^Display) -> uint --- @@ -1357,26 +1357,26 @@ foreign xlib { window: Window, start: Time, stop: Time, - nevents: ^i32 + nevents: ^i32, ) -> [^]XTimeCoord --- // Enabling or disabling synchronization XSetAfterFunction :: proc( display: ^Display, - procedure: #type proc "c" (display: ^Display) -> i32 + procedure: #type proc "c" (display: ^Display) -> i32, ) -> i32 --- XSynchronize :: proc( display: ^Display, - onoff: b32 + onoff: b32, ) -> i32 --- // Error handling XSetErrorHandler :: proc( - handler: #type proc "c" (display: ^Display, event: ^XErrorEvent) -> i32 + handler: #type proc "c" (display: ^Display, event: ^XErrorEvent) -> i32, ) -> i32 --- XGetErrorText :: proc( display: ^Display, code: i32, buffer: [^]u8, - size: i32 + size: i32, ) --- XGetErrorDatabaseText :: proc( display: ^Display, @@ -1384,11 +1384,11 @@ foreign xlib { message: cstring, default_string: cstring, buffer: [^]u8, - size: i32 + size: i32, ) --- XDisplayName :: proc(string: cstring) -> cstring --- XSetIOErrorHandler :: proc( - handler: #type proc "c" (display: ^Display) -> i32 + handler: #type proc "c" (display: ^Display) -> i32, ) -> i32 --- // Pointer grabbing XGrabPointer :: proc( @@ -1400,17 +1400,17 @@ foreign xlib { keyboard_mode: GrabMode, confine_to: Window, cursor: Cursor, - time: Time + time: Time, ) -> i32 --- XUngrabPointer :: proc( display: ^Display, - time: Time + time: Time, ) -> i32 --- XChangeActivePointerGrab :: proc( display: ^Display, event_mask: EventMask, cursor: Cursor, - time: Time + time: Time, ) --- XGrabButton :: proc( display: ^Display, @@ -1422,13 +1422,13 @@ foreign xlib { pointer_mode: GrabMode, keyboard_mode: GrabMode, confine_to: Window, - cursor: Cursor + cursor: Cursor, ) --- XUngrabButton :: proc( display: ^Display, button: u32, modifiers: InputMask, - grab_window: Window + grab_window: Window, ) --- XGrabKeyboard :: proc( display: ^Display, @@ -1436,11 +1436,11 @@ foreign xlib { owner_events: b32, pointer_mode: GrabMode, keyboard_mode: GrabMode, - time: Time + time: Time, ) -> i32 --- XUngrabKeyboard :: proc( display: ^Display, - time: Time + time: Time, ) --- XGrabKey :: proc( display: ^Display, @@ -1449,13 +1449,13 @@ foreign xlib { grab_window: Window, owner_events: b32, pointer_mode: GrabMode, - keyboard_mode: GrabMode + keyboard_mode: GrabMode, ) --- XUngrabKey :: proc( display: ^Display, keycode: i32, modifiers: InputMask, - grab_window: Window + grab_window: Window, ) --- // Resuming event processing XAllowEvents :: proc(display: ^Display, evend_mode: AllowEventsMode, time: Time) --- @@ -1469,29 +1469,29 @@ foreign xlib { src_width: u32, src_height: u32, dst_x: i32, - dst_y: i32 + dst_y: i32, ) --- // Controlling input focus XSetInputFocus :: proc( display: ^Display, focus: Window, revert_to: FocusRevert, - time: Time + time: Time, ) --- XGetInputFocus :: proc( display: ^Display, focus: ^Window, - revert_to: ^FocusRevert + revert_to: ^FocusRevert, ) --- // Manipulating the keyboard and pointer settings XChangeKeyboardControl :: proc( display: ^Display, mask: KeyboardControlMask, - values: ^XKeyboardControl + values: ^XKeyboardControl, ) --- XGetKeyboardControl :: proc( display: ^Display, - values: ^XKeyboardState + values: ^XKeyboardState, ) --- XAutoRepeatOn :: proc(display: ^Display) --- XAutoRepeatOff :: proc(display: ^Display) --- @@ -1505,43 +1505,43 @@ foreign xlib { do_threshold: b32, accel_numerator: i32, accel_denominator: i32, - threshold: i32 + threshold: i32, ) --- XGetPointerControl :: proc( display: ^Display, accel_numerator: ^i32, accel_denominator: ^i32, - threshold: ^i32 + threshold: ^i32, ) --- // Manipulating the keyboard encoding XDisplayKeycodes :: proc( display: ^Display, min_keycodes: ^i32, - max_keycodes: ^i32 + max_keycodes: ^i32, ) --- XGetKeyboardMapping :: proc( display: ^Display, first: KeyCode, count: i32, - keysyms_per: ^i32 + keysyms_per: ^i32, ) -> ^KeySym --- XChangeKeyboardMapping :: proc( display: ^Display, first: KeyCode, keysyms_per: i32, keysyms: [^]KeySym, - num_codes: i32 + num_codes: i32, ) --- XNewModifiermap :: proc(max_keys_per_mode: i32) -> ^XModifierKeymap --- XInsertModifiermapEntry :: proc( modmap: ^XModifierKeymap, keycode_entry: KeyCode, - modifier: i32 + modifier: i32, ) -> ^XModifierKeymap --- XDeleteModifiermapEntry :: proc( modmap: ^XModifierKeymap, keycode_entry: KeyCode, - modifier: i32 + modifier: i32, ) -> ^XModifierKeymap --- XFreeModifiermap :: proc(modmap: ^XModifierKeymap) --- XSetModifierMapping :: proc(display: ^Display, modmap: ^XModifierKeymap) -> i32 --- @@ -1568,7 +1568,7 @@ foreign xlib { XSetWMName :: proc( display: ^Display, window: Window, - prop: ^XTextProperty + prop: ^XTextProperty, ) --- XGetWMName :: proc( display: ^Display, @@ -1578,17 +1578,17 @@ foreign xlib { XStoreName :: proc( display: ^Display, window: Window, - name: cstring + name: cstring, ) --- XFetchName :: proc( display: ^Display, window: Window, - name: ^cstring + name: ^cstring, ) -> Status --- XSetWMIconName :: proc( display: ^Display, window: Window, - prop: ^XTextProperty + prop: ^XTextProperty, ) --- XGetWMIconName :: proc( display: ^Display, @@ -1676,7 +1676,7 @@ foreign xlib { display: ^Display, window: Window, protocols: ^[^]Atom, - count: ^i32 + count: ^i32, ) -> Status --- // Setting and reading the WM_COLORMAP_WINDOWS property XSetWMColormapWindows :: proc( @@ -1705,4 +1705,204 @@ foreign xlib { size_list: ^[^]XIconSize, count: ^i32, ) -> Status --- + // Using window manager convenience functions + XmbSetWMProperties :: proc( + display: ^Display, + window: Window, + window_name: cstring, + icon_name: cstring, + argv: [^]cstring, + argc: i32, + normal_hints: ^XSizeHints, + wm_hints: ^XWMHints, + class_hints: ^XClassHint, + ) --- + XSetWMProperties :: proc( + display: ^Display, + window: Window, + window_name: ^XTextProperty, + argv: [^]cstring, + argc: i32, + normal_hints: ^XSizeHints, + wm_hints: ^XWMHints, + class_hints: ^XWMHints, + ) --- + // Client to session manager communication + XSetCommand :: proc( + display: ^Display, + window: Window, + argv: [^]cstring, + argc: i32, + ) --- + XGetCommand :: proc( + display: ^Display, + window: Window, + argv: ^[^]cstring, + argc: ^i32, + ) -> Status --- + XSetWMClientMachine :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) --- + XGetWMClientMachine :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) -> Status --- + XSetRGBColormaps :: proc( + display: ^Display, + window: Window, + colormap: ^XStandardColormap, + prop: Atom, + ) --- + XGetRGBColormaps :: proc( + display: ^Display, + window: Window, + colormap: ^[^]XStandardColormap, + count: ^i32, + prop: Atom, + ) -> Status --- + // Keyboard utility functions + XLookupKeysym :: proc( + event: ^XKeyEvent, + index: i32, + ) -> KeySym --- + XKeycodeToKeysym :: proc( + display: ^Display, + keycode: KeyCode, + index: i32, + ) -> KeySym --- + XKeysymToKeycode :: proc( + display: ^Display, + keysym: KeySym, + ) -> KeyCode --- + XRefreshKeyboardMapping :: proc(event_map: ^XMappingEvent) --- + XConvertCase :: proc( + keysym: KeySym, + lower: ^KeySym, + upper: ^KeySym, + ) --- + XStringToKeysym :: proc(str: cstring) -> KeySym --- + XKeysymToString :: proc(keysym: KeySym) -> cstring --- + XLookupString :: proc( + event: ^XKeyEvent, + buffer: [^]u8, + count: i32, + keysym: ^KeySym, + status: ^XComposeStatus, + ) -> i32 --- + XRebindKeysym :: proc( + display: ^Display, + keysym: KeySym, + list: [^]KeySym, + mod_count: i32, + string: [^]u8, + num_bytes: i32, + ) --- + // Allocating permanent storage + XPermalloc :: proc(size: u32) -> rawptr --- + // Parsing the window geometry + XParseGeometry :: proc( + parsestring: cstring, + x_ret: ^i32, + y_ret: ^i32, + width: ^u32, + height: ^u32, + ) -> i32 --- + XWMGeometry :: proc( + display: ^Display, + screen_no: i32, + user_geom: cstring, + def_geom: cstring, + bwidth: u32, + hints: ^XSizeHints, + x_ret: ^i32, + y_ret: ^i32, + w_ret: ^u32, + h_ret: ^u32, + grav: ^Gravity, + ) -> i32 --- + // Creating, copying and destroying regions + XCreateRegion :: proc() -> Region --- + XPolygonRegion :: proc( + points: [^]XPoint, + n: i32, + fill: FillRule, + ) -> Region --- + XSetRegion :: proc( + display: ^Display, + gc: GC, + region: Region, + ) --- + XDestroyRegion :: proc(r: Region) --- + // Moving or shrinking regions + XOffsetRegion :: proc(region: Region, dx, dy: i32) --- + XShrinkRegion :: proc(region: Region, dx, dy: i32) --- + // Computing with regions + XClipBox :: proc(region: Region, rect: ^XRectangle) --- + XIntersectRegion :: proc(sra, srb, ret: Region) --- + XUnionRegion :: proc(sra, srb, ret: Region) --- + XUnionRectWithRegion :: proc(rect: ^XRectangle, src, dst: Region) --- + XSubtractRegion :: proc(sra, srb, ret: Region) --- + XXorRegion :: proc(sra, srb, ret: Region) --- + XEmptyRegion :: proc(reg: Region) -> b32 --- + XEqualRegion :: proc(a,b: Region) -> b32 --- + XPointInRegion :: proc(reg: Region, x,y: i32) -> b32 --- + XRectInRegion :: proc(reg: Region, x,y: i32, w,h: u32) -> b32 --- + // Using cut buffers + XStoreBytes :: proc(display: ^Display, bytes: [^]u8, nbytes: i32) --- + XStoreBuffer :: proc(display: ^Display, bytes: [^]u8, nbytes: i32, buffer: i32) --- + XFetchBytes :: proc(display: ^Display, nbytes: ^i32) -> [^]u8 --- + XFetchBuffer :: proc(display: ^Display, nbytes: ^i32, buffer: i32) -> [^]u8 --- + // Determining the appropriate visual types + XGetVisualInfo :: proc( + display: ^Display, + mask: VisualInfoMask, + info: ^XVisualInfo, + nret: ^i32, + ) -> [^]XVisualInfo --- + XMatchVisualInfo :: proc( + display: ^Display, + screen_no: i32, + depth: i32, + class: i32, + ret: ^XVisualInfo, + ) -> Status --- + // Manipulating images + XCreateImage :: proc( + display: ^Display, + visual: ^Visual, + depth: u32, + format: ImageFormat, + offset: i32, + data: rawptr, + width: u32, + height: u32, + pad: i32, + stride: i32, + ) -> ^XImage --- + XGetPixel :: proc( + image: ^XImage, + x: i32, + y: i32, + ) -> uint --- + XPutPixel :: proc( + image: ^XImage, + x: i32, + y: i32, + pixel: uint, + ) --- + XSubImage :: proc( + image: ^XImage, + x: i32, + y: i32, + w: u32, + h: u32, + ) -> ^XImage --- + XAddPixel :: proc( + image: ^XImage, + value: int, + ) --- + XDestroyImage :: proc(image: ^XImage) --- } diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin index 9122341f3..2411c038c 100644 --- a/vendor/x11/xlib/xlib_types.odin +++ b/vendor/x11/xlib/xlib_types.odin @@ -360,7 +360,7 @@ XMotionEvent :: struct { same_screen: b32, } -XPointerMovedEvent :: XMotionEvent; +XPointerMovedEvent :: XMotionEvent XCrossingEvent :: struct { type: EventType, From 1b770fc3b279d2b0529419ec0d6be9a0e6539b22 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 13 Nov 2023 19:45:26 +1100 Subject: [PATCH 053/160] [vendor/x11]: Correction on XPutImage definition --- vendor/x11/xlib/xlib_procs.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index dc2141624..1ea389620 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -1183,7 +1183,7 @@ foreign xlib { display: ^Display, drawable: Drawable, gc: GC, - image: XImage, + image: ^XImage, src_x: i32, src_y: i32, dst_x: i32, From 5f7843a13d457eff3bac837f0ce1e5ff1ed2a9dc Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 13 Nov 2023 19:49:23 +1100 Subject: [PATCH 054/160] [vendor/x11]: Correct system import for linux --- vendor/x11/xlib/xlib_procs.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index 1ea389620..7abe1dcc2 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -1,7 +1,7 @@ //+build linux, openbsd, freebsd package xlib -foreign import xlib "system:x11" +foreign import xlib "system:X11" foreign xlib { @(link_name="_Xdebug") _Xdebug: i32 } From 2cb5cc774df173b2c08724ab2a5474bde6177a14 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Mon, 13 Nov 2023 19:51:35 +1100 Subject: [PATCH 055/160] [vendor/x11]: Add build guards for other xlib files --- vendor/x11/xlib/xlib_const.odin | 2 +- vendor/x11/xlib/xlib_keysym.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin index 87b13479e..910940dec 100644 --- a/vendor/x11/xlib/xlib_const.odin +++ b/vendor/x11/xlib/xlib_const.odin @@ -1,4 +1,4 @@ - +//+build linux, freebsd, openbsd package xlib // Special values for many types. Most of these constants diff --git a/vendor/x11/xlib/xlib_keysym.odin b/vendor/x11/xlib/xlib_keysym.odin index c712bf784..594d966a4 100644 --- a/vendor/x11/xlib/xlib_keysym.odin +++ b/vendor/x11/xlib/xlib_keysym.odin @@ -1,4 +1,4 @@ - +//+build linux, freebsd, openbsd package xlib KeySym :: enum u32 { From 3e1791aa5c178cdae3f45bced10775a82abc361a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 13 Nov 2023 20:54:19 +0100 Subject: [PATCH 056/160] Fix typos --- core/io/io.odin | 2 +- core/runtime/core_builtin.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/io/io.odin b/core/io/io.odin index 566e13c54..d3cae7bce 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -34,7 +34,7 @@ Error :: enum i32 { // No_Progress is returned by some implementations of `io.Reader` when many calls // to `read` have failed to return any data or error. - // This is usually a signed of a broken `io.Reader` implementation + // This is usually a sign of a broken `io.Reader` implementation No_Progress, Invalid_Whence, diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index a73a3d712..0348a93df 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -109,7 +109,7 @@ remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_locatio // `pop` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. // -// Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic. +// Note: If the dynamic array has no elements (`len(array) == 0`), this procedure will panic. @builtin pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { assert(len(array) > 0, loc=loc) From b30ceab86481eb2171a1eb1041dc8d3177f06d69 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Tue, 14 Nov 2023 15:41:01 +0900 Subject: [PATCH 057/160] core/encoding/endian: Use intrinsics for loads/stores - Use `intrinsics.unaligned_load`/`intrinsics.unaligned_store` - Make all the routines contextless - Add unchecked variants for code that "Knows What It Is Doing(TM)" --- core/encoding/endian/endian.odin | 142 +++++++++++++++++-------------- 1 file changed, 76 insertions(+), 66 deletions(-) diff --git a/core/encoding/endian/endian.odin b/core/encoding/endian/endian.odin index 08bde3139..d70d873be 100644 --- a/core/encoding/endian/endian.odin +++ b/core/encoding/endian/endian.odin @@ -1,5 +1,8 @@ package encoding_endian +import "core:intrinsics" +import "core:math/bits" + Byte_Order :: enum u8 { Little, Big, @@ -7,147 +10,154 @@ Byte_Order :: enum u8 { PLATFORM_BYTE_ORDER :: Byte_Order.Little when ODIN_ENDIAN == .Little else Byte_Order.Big -get_u16 :: proc(b: []byte, order: Byte_Order) -> (v: u16, ok: bool) { +unchecked_get_u16le :: #force_inline proc "contextless" (b: []byte) -> u16 { + return bits.from_le_u16(intrinsics.unaligned_load((^u16)(raw_data(b)))) +} +unchecked_get_u32le :: #force_inline proc "contextless" (b: []byte) -> u32 { + return bits.from_le_u32(intrinsics.unaligned_load((^u32)(raw_data(b)))) +} +unchecked_get_u64le :: #force_inline proc "contextless" (b: []byte) -> u64 { + return bits.from_le_u64(intrinsics.unaligned_load((^u64)(raw_data(b)))) +} +unchecked_get_u16be :: #force_inline proc "contextless" (b: []byte) -> u16 { + return bits.from_be_u16(intrinsics.unaligned_load((^u16)(raw_data(b)))) +} +unchecked_get_u32be :: #force_inline proc "contextless" (b: []byte) -> u32 { + return bits.from_be_u32(intrinsics.unaligned_load((^u32)(raw_data(b)))) +} +unchecked_get_u64be :: #force_inline proc "contextless" (b: []byte) -> u64 { + return bits.from_be_u64(intrinsics.unaligned_load((^u64)(raw_data(b)))) +} + +get_u16 :: proc "contextless" (b: []byte, order: Byte_Order) -> (v: u16, ok: bool) { if len(b) < 2 { return 0, false } - #no_bounds_check if order == .Little { - v = u16(b[0]) | u16(b[1])<<8 + if order == .Little { + v = unchecked_get_u16le(b) } else { - v = u16(b[1]) | u16(b[0])<<8 + v = unchecked_get_u16be(b) } return v, true } -get_u32 :: proc(b: []byte, order: Byte_Order) -> (v: u32, ok: bool) { +get_u32 :: proc "contextless" (b: []byte, order: Byte_Order) -> (v: u32, ok: bool) { if len(b) < 4 { return 0, false } - #no_bounds_check if order == .Little { - v = u32(b[0]) | u32(b[1])<<8 | u32(b[2])<<16 | u32(b[3])<<24 + if order == .Little { + v = unchecked_get_u32le(b) } else { - v = u32(b[3]) | u32(b[2])<<8 | u32(b[1])<<16 | u32(b[0])<<24 + v = unchecked_get_u32be(b) } return v, true } - -get_u64 :: proc(b: []byte, order: Byte_Order) -> (v: u64, ok: bool) { +get_u64 :: proc "contextless" (b: []byte, order: Byte_Order) -> (v: u64, ok: bool) { if len(b) < 8 { return 0, false } - #no_bounds_check if order == .Little { - v = u64(b[0]) | u64(b[1])<<8 | u64(b[2])<<16 | u64(b[3])<<24 | - u64(b[4])<<32 | u64(b[5])<<40 | u64(b[6])<<48 | u64(b[7])<<56 + if order == .Little { + v = unchecked_get_u64le(b) } else { - v = u64(b[7]) | u64(b[6])<<8 | u64(b[5])<<16 | u64(b[4])<<24 | - u64(b[3])<<32 | u64(b[2])<<40 | u64(b[1])<<48 | u64(b[0])<<56 + v = unchecked_get_u64be(b) } return v, true } -get_i16 :: proc(b: []byte, order: Byte_Order) -> (i16, bool) { +get_i16 :: proc "contextless" (b: []byte, order: Byte_Order) -> (i16, bool) { v, ok := get_u16(b, order) return i16(v), ok } -get_i32 :: proc(b: []byte, order: Byte_Order) -> (i32, bool) { +get_i32 :: proc "contextless" (b: []byte, order: Byte_Order) -> (i32, bool) { v, ok := get_u32(b, order) return i32(v), ok } -get_i64 :: proc(b: []byte, order: Byte_Order) -> (i64, bool) { +get_i64 :: proc "contextless" (b: []byte, order: Byte_Order) -> (i64, bool) { v, ok := get_u64(b, order) return i64(v), ok } -get_f16 :: proc(b: []byte, order: Byte_Order) -> (f16, bool) { +get_f16 :: proc "contextless" (b: []byte, order: Byte_Order) -> (f16, bool) { v, ok := get_u16(b, order) return transmute(f16)v, ok } -get_f32 :: proc(b: []byte, order: Byte_Order) -> (f32, bool) { +get_f32 :: proc "contextless" (b: []byte, order: Byte_Order) -> (f32, bool) { v, ok := get_u32(b, order) return transmute(f32)v, ok } -get_f64 :: proc(b: []byte, order: Byte_Order) -> (f64, bool) { +get_f64 :: proc "contextless" (b: []byte, order: Byte_Order) -> (f64, bool) { v, ok := get_u64(b, order) return transmute(f64)v, ok } +unchecked_put_u16le :: #force_inline proc "contextless" (b: []byte, v: u16) { + intrinsics.unaligned_store((^u16)(raw_data(b)), bits.to_le_u16(v)) +} +unchecked_put_u32le :: #force_inline proc "contextless" (b: []byte, v: u32) { + intrinsics.unaligned_store((^u32)(raw_data(b)), bits.to_le_u32(v)) +} +unchecked_put_u64le :: #force_inline proc "contextless" (b: []byte, v: u64) { + intrinsics.unaligned_store((^u64)(raw_data(b)), bits.to_le_u64(v)) +} +unchecked_put_u16be :: #force_inline proc "contextless" (b: []byte, v: u16) { + intrinsics.unaligned_store((^u16)(raw_data(b)), bits.to_be_u16(v)) +} +unchecked_put_u32be :: #force_inline proc "contextless" (b: []byte, v: u32) { + intrinsics.unaligned_store((^u32)(raw_data(b)), bits.to_be_u32(v)) +} +unchecked_put_u64be :: #force_inline proc "contextless" (b: []byte, v: u64) { + intrinsics.unaligned_store((^u64)(raw_data(b)), bits.to_be_u64(v)) +} -put_u16 :: proc(b: []byte, order: Byte_Order, v: u16) -> bool { +put_u16 :: proc "contextless" (b: []byte, order: Byte_Order, v: u16) -> bool { if len(b) < 2 { return false } - #no_bounds_check if order == .Little { - b[0] = byte(v) - b[1] = byte(v >> 8) + if order == .Little { + unchecked_put_u16le(b, v) } else { - b[0] = byte(v >> 8) - b[1] = byte(v) + unchecked_put_u16be(b, v) } return true } -put_u32 :: proc(b: []byte, order: Byte_Order, v: u32) -> bool { +put_u32 :: proc "contextless" (b: []byte, order: Byte_Order, v: u32) -> bool { if len(b) < 4 { return false } - #no_bounds_check if order == .Little { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) + if order == .Little { + unchecked_put_u32le(b, v) } else { - b[0] = byte(v >> 24) - b[1] = byte(v >> 16) - b[2] = byte(v >> 8) - b[3] = byte(v) + unchecked_put_u32be(b, v) } return true } -put_u64 :: proc(b: []byte, order: Byte_Order, v: u64) -> bool { +put_u64 :: proc "contextless" (b: []byte, order: Byte_Order, v: u64) -> bool { if len(b) < 8 { return false } - #no_bounds_check if order == .Little { - b[0] = byte(v >> 0) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - b[4] = byte(v >> 32) - b[5] = byte(v >> 40) - b[6] = byte(v >> 48) - b[7] = byte(v >> 56) + if order == .Little { + unchecked_put_u64le(b, v) } else { - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) + unchecked_put_u64be(b, v) } return true } -put_i16 :: proc(b: []byte, order: Byte_Order, v: i16) -> bool { +put_i16 :: proc "contextless" (b: []byte, order: Byte_Order, v: i16) -> bool { return put_u16(b, order, u16(v)) } - -put_i32 :: proc(b: []byte, order: Byte_Order, v: i32) -> bool { +put_i32 :: proc "contextless" (b: []byte, order: Byte_Order, v: i32) -> bool { return put_u32(b, order, u32(v)) } - -put_i64 :: proc(b: []byte, order: Byte_Order, v: i64) -> bool { +put_i64 :: proc "contextless" (b: []byte, order: Byte_Order, v: i64) -> bool { return put_u64(b, order, u64(v)) } - -put_f16 :: proc(b: []byte, order: Byte_Order, v: f16) -> bool { +put_f16 :: proc "contextless" (b: []byte, order: Byte_Order, v: f16) -> bool { return put_u16(b, order, transmute(u16)v) } - -put_f32 :: proc(b: []byte, order: Byte_Order, v: f32) -> bool { +put_f32 :: proc "contextless" (b: []byte, order: Byte_Order, v: f32) -> bool { return put_u32(b, order, transmute(u32)v) } - -put_f64 :: proc(b: []byte, order: Byte_Order, v: f64) -> bool { +put_f64 :: proc "contextless" (b: []byte, order: Byte_Order, v: f64) -> bool { return put_u64(b, order, transmute(u64)v) } From 1b3fb11a312ce842b9f3c0b9a30d03ec6e8fe8aa Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Tue, 14 Nov 2023 15:45:14 +0900 Subject: [PATCH 058/160] core/encoding/endian: Tidy up a comment (NFC) --- core/encoding/endian/doc.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/encoding/endian/doc.odin b/core/encoding/endian/doc.odin index 754ffa583..8ebefd0a4 100644 --- a/core/encoding/endian/doc.odin +++ b/core/encoding/endian/doc.odin @@ -1,5 +1,5 @@ /* - Package endian implements sa simple translation between bytes and numbers with + Package endian implements a simple translation between bytes and numbers with specific endian encodings. buf: [100]u8 From 9e5e49a65daf1f189e49c0eade7d90d148e7ac71 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 14 Nov 2023 16:53:30 +0100 Subject: [PATCH 059/160] checker: suggest ..[]T when passing a slice to variadic arg ..T --- src/check_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5cc548739..5a8b57df6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5652,6 +5652,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } else { if (show_error) { check_assignment(c, o, param_type, str_lit("procedure argument")); + + Type *src = base_type(o->type); + Type *dst = base_type(param_type); + if (is_type_slice(src) && are_types_identical(src->Slice.elem, dst)) { + gbString a = expr_to_string(o->expr); + error_line("\tSuggestion: Did you mean to pass the slice into the variadic parameter with ..%s?\n\n", a); + gb_string_free(a); + } } err = CallArgumentError_WrongTypes; } From 04c928fb9ed8ab7aca44b0775251c98f8eb4250e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 15 Nov 2023 15:20:52 +0100 Subject: [PATCH 060/160] Clear up core:container/queue --- core/container/queue/queue.odin | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/core/container/queue/queue.odin b/core/container/queue/queue.odin index 5783cbc6c..bdc61c2a6 100644 --- a/core/container/queue/queue.odin +++ b/core/container/queue/queue.odin @@ -22,7 +22,9 @@ init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := contex return reserve(q, capacity) } -// Procedure to initialize a queue from a fixed backing slice +// Procedure to initialize a queue from a fixed backing slice. +// The contents of the `backing` will be overwritten as items are pushed onto the `Queue`. +// Any previous contents are not available. init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { clear(q) q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{ @@ -34,6 +36,21 @@ init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { return true } +// Procedure to initialize a queue from a fixed backing slice. +// Existing contents are preserved and available on the queue. +init_with_contents :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { + clear(q) + q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{ + data = raw_data(backing), + len = builtin.len(backing), + cap = builtin.len(backing), + allocator = {procedure=runtime.nil_allocator_proc, data=nil}, + } + q.len = len(backing) + q.offset = len(backing) + return true +} + // Procedure to destroy a queue destroy :: proc(q: ^$Q/Queue($T)) { delete(q.data) From 6b9202dfbf25a022287583197e57dbcd9159ea63 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 12 Nov 2023 02:02:30 +0100 Subject: [PATCH 061/160] -no-crt and assembly compilation on darwin --- core/runtime/entry_unix.odin | 11 ++--- .../entry_unix_no_crt_darwin_arm64.asm | 20 +++++++++ core/runtime/os_specific_any.odin | 2 +- core/runtime/os_specific_darwin.odin | 12 ++++++ src/checker.cpp | 2 +- src/linker.cpp | 42 ++++++++++++------- 6 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 core/runtime/entry_unix_no_crt_darwin_arm64.asm create mode 100644 core/runtime/os_specific_darwin.odin diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index 0c718445a..78e545c22 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -26,8 +26,13 @@ when ODIN_BUILD_MODE == .Dynamic { // to retrieve argc and argv from the stack when ODIN_ARCH == .amd64 { @require foreign import entry "entry_unix_no_crt_amd64.asm" + SYS_exit :: 60 } else when ODIN_ARCH == .i386 { @require foreign import entry "entry_unix_no_crt_i386.asm" + SYS_exit :: 1 + } else when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 { + @require foreign import entry "entry_unix_no_crt_darwin_arm64.asm" + SYS_exit :: 1 } @(link_name="_start_odin", linkage="strong", require) _start_odin :: proc "c" (argc: i32, argv: [^]cstring) -> ! { @@ -36,11 +41,7 @@ when ODIN_BUILD_MODE == .Dynamic { #force_no_inline _startup_runtime() intrinsics.__entry_point() #force_no_inline _cleanup_runtime() - when ODIN_ARCH == .amd64 { - intrinsics.syscall(/*SYS_exit = */60) - } else when ODIN_ARCH == .i386 { - intrinsics.syscall(/*SYS_exit = */1) - } + intrinsics.syscall(SYS_exit, 0) unreachable() } } else { diff --git a/core/runtime/entry_unix_no_crt_darwin_arm64.asm b/core/runtime/entry_unix_no_crt_darwin_arm64.asm new file mode 100644 index 000000000..0f71fbdf8 --- /dev/null +++ b/core/runtime/entry_unix_no_crt_darwin_arm64.asm @@ -0,0 +1,20 @@ + .section __TEXT,__text + + ; NOTE(laytan): this should ideally be the -minimum-os-version flag but there is no nice way of preprocessing assembly in Odin. + ; 10 seems to be the lowest it goes and I don't see it mess with any targeted os version so this seems fine. + .build_version macos, 10, 0 + + .extern __start_odin + + .global _main + .align 2 +_main: + mov x5, sp ; use x5 as the stack pointer + + str x0, [x5] ; get argc into x0 (kernel passes 32-bit int argc as 64-bits on stack to keep alignment) + str x1, [x5, #8] ; get argv into x1 + + and sp, x5, #~15 ; force 16-byte alignment of the stack + + bl __start_odin ; call into Odin entry point + ret ; should never get here diff --git a/core/runtime/os_specific_any.odin b/core/runtime/os_specific_any.odin index afa106138..5fffceeeb 100644 --- a/core/runtime/os_specific_any.odin +++ b/core/runtime/os_specific_any.odin @@ -1,4 +1,4 @@ -//+build !freestanding !wasi !windows !js +//+build !freestanding !wasi !windows !js !darwin package runtime import "core:os" diff --git a/core/runtime/os_specific_darwin.odin b/core/runtime/os_specific_darwin.odin new file mode 100644 index 000000000..33136c92f --- /dev/null +++ b/core/runtime/os_specific_darwin.odin @@ -0,0 +1,12 @@ +//+build darwin +package runtime + +import "core:intrinsics" + +_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { + ret := intrinsics.syscall(4, 1, uintptr(raw_data(data)), uintptr(len(data))) + if ret < 0 { + return 0, _OS_Errno(-ret) + } + return int(ret), 0 +} diff --git a/src/checker.cpp b/src/checker.cpp index 29f22bd9c..0366cf05d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4733,7 +4733,7 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { } if (has_asm_extension(fullpath)) { - if (build_context.metrics.arch != TargetArch_amd64) { + if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.os != TargetOs_darwin) { error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s", LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch])); } diff --git a/src/linker.cpp b/src/linker.cpp index eb3687ae2..c3ede0f55 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -337,20 +337,34 @@ gb_internal i32 linker_stage(LinkerData *gen) { obj_format = str_lit("elf32"); } #endif // GB_ARCH_*_BIT - // Note(bumbread): I'm assuming nasm is installed on the host machine. - // Shipping binaries on unix-likes gets into the weird territorry of - // "which version of glibc" is it linked with. - result = system_exec_command_line_app("nasm", - "nasm \"%.*s\" " - "-f \"%.*s\" " - "-o \"%.*s\" " - "%.*s " - "", - LIT(asm_file), - LIT(obj_format), - LIT(obj_file), - LIT(build_context.extra_assembler_flags) - ); + + if (is_osx) { + // `as` comes with MacOS. + result = system_exec_command_line_app("as", + "as \"%.*s\" " + "-o \"%.*s\" " + "%.*s " + "", + LIT(asm_file), + LIT(obj_file), + LIT(build_context.extra_assembler_flags) + ); + } else { + // Note(bumbread): I'm assuming nasm is installed on the host machine. + // Shipping binaries on unix-likes gets into the weird territorry of + // "which version of glibc" is it linked with. + result = system_exec_command_line_app("nasm", + "nasm \"%.*s\" " + "-f \"%.*s\" " + "-o \"%.*s\" " + "%.*s " + "", + LIT(asm_file), + LIT(obj_format), + LIT(obj_file), + LIT(build_context.extra_assembler_flags) + ); + } array_add(&gen->output_object_paths, obj_file); } else { if (string_set_update(&libs, lib)) { From 9078ddaf5a89b1b8d46f0fa7d86dee027f686f5a Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 9 Nov 2023 12:12:01 +0100 Subject: [PATCH 062/160] Allow larger thread poly data The poly data currently has the restriction of being less than a pointer's size, but there is much more space in the `Thread.user_args` array which can be utilized, this commit allows you to pass types that are larger than pointer length as long as the total size of the poly data is less than that of the `Thread.user_args`. --- core/thread/thread.odin | 93 +++++++++++++++---------- tests/core/Makefile | 5 +- tests/core/build.bat | 5 ++ tests/core/thread/test_core_thread.odin | 80 +++++++++++++++++++++ 4 files changed, 144 insertions(+), 39 deletions(-) create mode 100644 tests/core/thread/test_core_thread.odin diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 9ba03203f..9fcc5b84f 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -116,26 +116,21 @@ run_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe( } run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) - where size_of(T) <= size_of(rawptr) { + where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { create_and_start_with_poly_data(data, fn, init_context, priority, true) } run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) - where size_of(T1) <= size_of(rawptr), - size_of(T2) <= size_of(rawptr) { + where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true) } run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) - where size_of(T1) <= size_of(rawptr), - size_of(T2) <= size_of(rawptr), - size_of(T3) <= size_of(rawptr) { + where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true) } run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) - where size_of(T1) <= size_of(rawptr), - size_of(T2) <= size_of(rawptr), - size_of(T3) <= size_of(rawptr) { + where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS { create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true) } @@ -178,7 +173,7 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co } create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread - where size_of(T) <= size_of(rawptr) { + where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T))t.data assert(t.user_index >= 1) @@ -188,96 +183,118 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex t := create(thread_proc, priority) t.data = rawptr(fn) t.user_index = 1 + data := data - mem.copy(&t.user_args[0], &data, size_of(data)) + + mem.copy(&t.user_args[0], &data, size_of(T)) + if self_cleanup { t.flags += {.Self_Cleanup} } + t.init_context = init_context start(t) return t } create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread - where size_of(T1) <= size_of(rawptr), - size_of(T2) <= size_of(rawptr) { + where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2))t.data assert(t.user_index >= 2) - arg1 := (^T1)(&t.user_args[0])^ - arg2 := (^T2)(&t.user_args[1])^ + + user_args := mem.slice_to_bytes(t.user_args[:]) + arg1 := (^T1)(raw_data(user_args))^ + arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^ + fn(arg1, arg2) } t := create(thread_proc, priority) t.data = rawptr(fn) t.user_index = 2 + arg1, arg2 := arg1, arg2 - mem.copy(&t.user_args[0], &arg1, size_of(arg1)) - mem.copy(&t.user_args[1], &arg2, size_of(arg2)) + user_args := mem.slice_to_bytes(t.user_args[:]) + + n := copy(user_args, mem.ptr_to_bytes(&arg1)) + _ = copy(user_args[n:], mem.ptr_to_bytes(&arg2)) + if self_cleanup { t.flags += {.Self_Cleanup} } + t.init_context = init_context start(t) return t } create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread - where size_of(T1) <= size_of(rawptr), - size_of(T2) <= size_of(rawptr), - size_of(T3) <= size_of(rawptr) { + where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2, T3))t.data assert(t.user_index >= 3) - arg1 := (^T1)(&t.user_args[0])^ - arg2 := (^T2)(&t.user_args[1])^ - arg3 := (^T3)(&t.user_args[2])^ + + user_args := mem.slice_to_bytes(t.user_args[:]) + arg1 := (^T1)(raw_data(user_args))^ + arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^ + arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^ + fn(arg1, arg2, arg3) } t := create(thread_proc, priority) t.data = rawptr(fn) t.user_index = 3 + arg1, arg2, arg3 := arg1, arg2, arg3 - mem.copy(&t.user_args[0], &arg1, size_of(arg1)) - mem.copy(&t.user_args[1], &arg2, size_of(arg2)) - mem.copy(&t.user_args[2], &arg3, size_of(arg3)) + user_args := mem.slice_to_bytes(t.user_args[:]) + + n := copy(user_args, mem.ptr_to_bytes(&arg1)) + n += copy(user_args[n:], mem.ptr_to_bytes(&arg2)) + _ = copy(user_args[n:], mem.ptr_to_bytes(&arg3)) + if self_cleanup { t.flags += {.Self_Cleanup} } + t.init_context = init_context start(t) return t } create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread - where size_of(T1) <= size_of(rawptr), - size_of(T2) <= size_of(rawptr), - size_of(T3) <= size_of(rawptr) { + where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2, T3, T4))t.data assert(t.user_index >= 4) - arg1 := (^T1)(&t.user_args[0])^ - arg2 := (^T2)(&t.user_args[1])^ - arg3 := (^T3)(&t.user_args[2])^ - arg4 := (^T4)(&t.user_args[3])^ + + user_args := mem.slice_to_bytes(t.user_args[:]) + arg1 := (^T1)(raw_data(user_args))^ + arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^ + arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^ + arg4 := (^T4)(raw_data(user_args[size_of(T1) + size_of(T2) + size_of(T3):]))^ + fn(arg1, arg2, arg3, arg4) } t := create(thread_proc, priority) t.data = rawptr(fn) t.user_index = 4 + arg1, arg2, arg3, arg4 := arg1, arg2, arg3, arg4 - mem.copy(&t.user_args[0], &arg1, size_of(arg1)) - mem.copy(&t.user_args[1], &arg2, size_of(arg2)) - mem.copy(&t.user_args[2], &arg3, size_of(arg3)) - mem.copy(&t.user_args[3], &arg4, size_of(arg4)) + user_args := mem.slice_to_bytes(t.user_args[:]) + + n := copy(user_args, mem.ptr_to_bytes(&arg1)) + n += copy(user_args[n:], mem.ptr_to_bytes(&arg2)) + n += copy(user_args[n:], mem.ptr_to_bytes(&arg3)) + _ = copy(user_args[n:], mem.ptr_to_bytes(&arg4)) + if self_cleanup { t.flags += {.Self_Cleanup} } + t.init_context = init_context start(t) return t } - _select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context { ctx, ok := init_context.? if !ok { diff --git a/tests/core/Makefile b/tests/core/Makefile index 919262f85..3fdadc246 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -3,7 +3,7 @@ PYTHON=$(shell which python3) all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test match_test c_libc_test net_test \ - fmt_test + fmt_test thread_test download_test_assets: $(PYTHON) download_assets.py @@ -61,3 +61,6 @@ net_test: fmt_test: $(ODIN) run fmt -out:test_core_fmt + +thread_test: + $(ODIN) run thread -out:test_core_thread diff --git a/tests/core/build.bat b/tests/core/build.bat index 1d146c8a4..311c9c78e 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -85,3 +85,8 @@ echo --- echo Running core:container tests echo --- %PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b + +echo --- +echo Running core:thread tests +echo --- +%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin new file mode 100644 index 000000000..e02fcc0f7 --- /dev/null +++ b/tests/core/thread/test_core_thread.odin @@ -0,0 +1,80 @@ +package test_core_thread + +import "core:testing" +import "core:thread" +import "core:fmt" +import "core:os" + +TEST_count := 0 +TEST_fail := 0 + +t := &testing.T{} + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + poly_data_test(t) + + if TEST_fail > 0 { + os.exit(1) + } +} + +@(test) +poly_data_test :: proc(_t: ^testing.T) { + MAX :: size_of(rawptr) * thread.MAX_USER_ARGUMENTS + + @static t: ^testing.T + t = _t + + b: [MAX]byte = 8 + t1 := thread.create_and_start_with_poly_data(b, proc(b: [MAX]byte) { + b_expect: [MAX]byte = 8 + expect(t, b == b_expect, "thread poly data not correct") + }, self_cleanup = true) + + b1: [3]uintptr = 1 + b2: [MAX / 2]byte = 3 + t2 := thread.create_and_start_with_poly_data2(b1, b2, proc(b: [3]uintptr, b2: [MAX / 2]byte) { + b_expect: [3]uintptr = 1 + b2_expect: [MAX / 2]byte = 3 + expect(t, b == b_expect, "thread poly data not correct") + expect(t, b2 == b2_expect, "thread poly data not correct") + }, self_cleanup = true) + + t3 := thread.create_and_start_with_poly_data3(b1, b2, uintptr(333), proc(b: [3]uintptr, b2: [MAX / 2]byte, b3: uintptr) { + b_expect: [3]uintptr = 1 + b2_expect: [MAX / 2]byte = 3 + + expect(t, b == b_expect, "thread poly data not correct") + expect(t, b2 == b2_expect, "thread poly data not correct") + expect(t, b3 == 333, "thread poly data not correct") + }, self_cleanup = true) + + t4 := thread.create_and_start_with_poly_data4(uintptr(111), b1, uintptr(333), u8(5), proc(n: uintptr, b: [3]uintptr, n2: uintptr, n4: u8) { + b_expect: [3]uintptr = 1 + + expect(t, n == 111, "thread poly data not correct") + expect(t, b == b_expect, "thread poly data not correct") + expect(t, n2 == 333, "thread poly data not correct") + expect(t, n4 == 5, "thread poly data not correct") + }, self_cleanup = true) + + thread.join_multiple(t1, t2, t3, t4) +} From 50f86dc14f0575efb52d93953f611157e1026453 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 9 Nov 2023 22:50:52 +0100 Subject: [PATCH 063/160] Fix shadowing --- tests/core/thread/test_core_thread.odin | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin index e02fcc0f7..441b2187f 100644 --- a/tests/core/thread/test_core_thread.odin +++ b/tests/core/thread/test_core_thread.odin @@ -40,13 +40,13 @@ main :: proc() { poly_data_test :: proc(_t: ^testing.T) { MAX :: size_of(rawptr) * thread.MAX_USER_ARGUMENTS - @static t: ^testing.T - t = _t + @static poly_data_test_t: ^testing.T + poly_data_test_t = _t b: [MAX]byte = 8 t1 := thread.create_and_start_with_poly_data(b, proc(b: [MAX]byte) { b_expect: [MAX]byte = 8 - expect(t, b == b_expect, "thread poly data not correct") + expect(poly_data_test_t, b == b_expect, "thread poly data not correct") }, self_cleanup = true) b1: [3]uintptr = 1 @@ -54,26 +54,26 @@ poly_data_test :: proc(_t: ^testing.T) { t2 := thread.create_and_start_with_poly_data2(b1, b2, proc(b: [3]uintptr, b2: [MAX / 2]byte) { b_expect: [3]uintptr = 1 b2_expect: [MAX / 2]byte = 3 - expect(t, b == b_expect, "thread poly data not correct") - expect(t, b2 == b2_expect, "thread poly data not correct") + expect(poly_data_test_t, b == b_expect, "thread poly data not correct") + expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") }, self_cleanup = true) t3 := thread.create_and_start_with_poly_data3(b1, b2, uintptr(333), proc(b: [3]uintptr, b2: [MAX / 2]byte, b3: uintptr) { b_expect: [3]uintptr = 1 b2_expect: [MAX / 2]byte = 3 - expect(t, b == b_expect, "thread poly data not correct") - expect(t, b2 == b2_expect, "thread poly data not correct") - expect(t, b3 == 333, "thread poly data not correct") + expect(poly_data_test_t, b == b_expect, "thread poly data not correct") + expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") + expect(poly_data_test_t, b3 == 333, "thread poly data not correct") }, self_cleanup = true) t4 := thread.create_and_start_with_poly_data4(uintptr(111), b1, uintptr(333), u8(5), proc(n: uintptr, b: [3]uintptr, n2: uintptr, n4: u8) { b_expect: [3]uintptr = 1 - expect(t, n == 111, "thread poly data not correct") - expect(t, b == b_expect, "thread poly data not correct") - expect(t, n2 == 333, "thread poly data not correct") - expect(t, n4 == 5, "thread poly data not correct") + expect(poly_data_test_t, n == 111, "thread poly data not correct") + expect(poly_data_test_t, b == b_expect, "thread poly data not correct") + expect(poly_data_test_t, n2 == 333, "thread poly data not correct") + expect(poly_data_test_t, n4 == 5, "thread poly data not correct") }, self_cleanup = true) thread.join_multiple(t1, t2, t3, t4) From 12b370ddc11d6cb3a044c2210d0af40e09c1e18b Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 15:36:39 +0900 Subject: [PATCH 064/160] repo: Add more test binaries to .gitignore --- .gitignore | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.gitignore b/.gitignore index 59b5adb6d..1f55b7ab7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,29 @@ bld/ tests/documentation/verify/ tests/documentation/all.odin-doc tests/internal/test_map +tests/internal/test_pow tests/internal/test_rtti +tests/core/test_core_compress +tests/core/test_core_filepath +tests/core/test_core_fmt +tests/core/test_core_i18n +tests/core/test_core_image +tests/core/test_core_libc +tests/core/test_core_match +tests/core/test_core_math +tests/core/test_core_net +tests/core/test_core_os_exit +tests/core/test_core_reflect +tests/core/test_core_strings +tests/core/test_crypto_hash +tests/core/test_hash +tests/core/test_hxa +tests/core/test_json +tests/core/test_linalg_glsl_math +tests/core/test_noise +tests/core/test_varint +tests/core/test_xml +tests/vendor/vendor_botan # Visual Studio 2015 cache/options directory .vs/ # Visual Studio Code options directory From d6e0e5d3f64056f70da82a272e94bc1a4a79d1ee Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 10:13:27 +0900 Subject: [PATCH 065/160] core/crypto/blake2: odinfmt (NFC) --- core/crypto/_blake2/blake2.odin | 67 ++++++++++-------- core/crypto/blake2b/blake2b.odin | 112 +++++++++++++++---------------- core/crypto/blake2s/blake2s.odin | 112 +++++++++++++++---------------- 3 files changed, 152 insertions(+), 139 deletions(-) diff --git a/core/crypto/_blake2/blake2.odin b/core/crypto/_blake2/blake2.odin index 7b75541e9..55ef2d6c9 100644 --- a/core/crypto/_blake2/blake2.odin +++ b/core/crypto/_blake2/blake2.odin @@ -12,10 +12,10 @@ package _blake2 import "../util" -BLAKE2S_BLOCK_SIZE :: 64 -BLAKE2S_SIZE :: 32 -BLAKE2B_BLOCK_SIZE :: 128 -BLAKE2B_SIZE :: 64 +BLAKE2S_BLOCK_SIZE :: 64 +BLAKE2S_SIZE :: 32 +BLAKE2B_BLOCK_SIZE :: 128 +BLAKE2B_SIZE :: 64 Blake2s_Context :: struct { h: [8]u32, @@ -28,7 +28,7 @@ Blake2s_Context :: struct { is_keyed: bool, size: byte, is_last_node: bool, - cfg: Blake2_Config, + cfg: Blake2_Config, } Blake2b_Context :: struct { @@ -42,15 +42,17 @@ Blake2b_Context :: struct { is_keyed: bool, size: byte, is_last_node: bool, - cfg: Blake2_Config, + cfg: Blake2_Config, } Blake2_Config :: struct { - size: byte, - key: []byte, - salt: []byte, + size: byte, + key: []byte, + salt: []byte, person: []byte, - tree: union{Blake2_Tree}, + tree: union { + Blake2_Tree, + }, } Blake2_Tree :: struct { @@ -108,8 +110,8 @@ init :: proc(ctx: ^$T) { p[3] = ctx.cfg.tree.(Blake2_Tree).max_depth util.PUT_U32_LE(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size) when T == Blake2s_Context { - p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset) - p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8) + p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset) + p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8) p[10] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 16) p[11] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 24) p[12] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 32) @@ -142,7 +144,7 @@ init :: proc(ctx: ^$T) { ctx.is_keyed = true } copy(ctx.ih[:], ctx.h[:]) - copy(ctx.h[:], ctx.ih[:]) + copy(ctx.h[:], ctx.ih[:]) if ctx.is_keyed { update(ctx, ctx.padded_key[:]) } @@ -229,7 +231,7 @@ blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) { ctx.f[0] = 0xffffffffffffffff if ctx.is_last_node { ctx.f[1] = 0xffffffffffffffff - } + } blocks(ctx, ctx.x[:]) @@ -257,16 +259,17 @@ blocks :: proc "contextless" (ctx: ^$T, p: []byte) { } blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []byte) { - h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] + h0, h1, h2, h3, h4, h5, h6, h7 := + ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] p := p for len(p) >= BLAKE2S_BLOCK_SIZE { ctx.t[0] += BLAKE2S_BLOCK_SIZE if ctx.t[0] < BLAKE2S_BLOCK_SIZE { ctx.t[1] += 1 - } + } v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 - v8 := BLAKE2S_IV[0] - v9 := BLAKE2S_IV[1] + v8 := BLAKE2S_IV[0] + v9 := BLAKE2S_IV[1] v10 := BLAKE2S_IV[2] v11 := BLAKE2S_IV[3] v12 := BLAKE2S_IV[4] ~ ctx.t[0] @@ -1409,17 +1412,19 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] h7 ~= v7 ~ v15 p = p[BLAKE2S_BLOCK_SIZE:] } - ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 + ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = + h0, h1, h2, h3, h4, h5, h6, h7 } blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []byte) { - h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] + h0, h1, h2, h3, h4, h5, h6, h7 := + ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] p := p for len(p) >= BLAKE2B_BLOCK_SIZE { ctx.t[0] += BLAKE2B_BLOCK_SIZE if ctx.t[0] < BLAKE2B_BLOCK_SIZE { - ctx.t[1]+=1 - } + ctx.t[1] += 1 + } v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 v8 := BLAKE2B_IV[0] v9 := BLAKE2B_IV[1] @@ -1431,9 +1436,16 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v15 := BLAKE2B_IV[7] ~ ctx.f[1] m: [16]u64 = --- j := 0 - for i := 0; i < 16; i+=1 { - m[i] = u64(p[j]) | u64(p[j + 1]) << 8 | u64(p[j + 2]) << 16 | u64(p[j + 3]) << 24 | - u64(p[j + 4]) << 32 | u64(p[j + 5]) << 40 | u64(p[j + 6]) << 48 | u64(p[j + 7]) << 56 + for i := 0; i < 16; i += 1 { + m[i] = + u64(p[j]) | + u64(p[j + 1]) << 8 | + u64(p[j + 2]) << 16 | + u64(p[j + 3]) << 24 | + u64(p[j + 4]) << 32 | + u64(p[j + 5]) << 40 | + u64(p[j + 6]) << 48 | + u64(p[j + 7]) << 56 j += 8 } v0 += m[0] @@ -2790,5 +2802,6 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] h7 ~= v7 ~ v15 p = p[BLAKE2B_BLOCK_SIZE:] } - ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 -} \ No newline at end of file + ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = + h0, h1, h2, h3, h4, h5, h6, h7 +} diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index 8f0770f82..caa1758fe 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -7,12 +7,12 @@ package blake2b List of contributors: zhibog, dotbmp: Initial implementation. - Interface for the BLAKE2B hashing algorithm. - BLAKE2B and BLAKE2B share the implementation in the _blake2 package. + Interface for the BLAKE2b hashing algorithm. + BLAKE2b and BLAKE2s share the implementation in the _blake2 package. */ -import "core:os" import "core:io" +import "core:os" import "../_blake2" @@ -25,87 +25,87 @@ DIGEST_SIZE :: 64 // hash_string will hash the given input and return the // computed hash hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) + return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2b_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2B_SIZE - ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE]byte + ctx: _blake2.Blake2b_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2B_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: _blake2.Blake2b_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2B_SIZE - ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash) + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: _blake2.Blake2b_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2B_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2b_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2B_SIZE - ctx.cfg = cfg - _blake2.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _blake2.update(&ctx, buf[:read]) - } - } - _blake2.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE]byte + ctx: _blake2.Blake2b_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2B_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _blake2.update(&ctx, buf[:read]) + } + } + _blake2.final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [DIGEST_SIZE]byte{}, false } hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, + hash_stream, + hash_file, + hash_bytes, + hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -115,13 +115,13 @@ hash :: proc { Blake2b_Context :: _blake2.Blake2b_Context init :: proc(ctx: ^_blake2.Blake2b_Context) { - _blake2.init(ctx) + _blake2.init(ctx) } update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) { - _blake2.update(ctx, data) + _blake2.update(ctx, data) } final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) { - _blake2.final(ctx, hash) + _blake2.final(ctx, hash) } diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index 6a2d4ab9b..db9dcab38 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -7,12 +7,12 @@ package blake2s List of contributors: zhibog, dotbmp: Initial implementation. - Interface for the BLAKE2S hashing algorithm. - BLAKE2B and BLAKE2B share the implementation in the _blake2 package. + Interface for the BLAKE2s hashing algorithm. + BLAKE2s and BLAKE2b share the implementation in the _blake2 package. */ -import "core:os" import "core:io" +import "core:os" import "../_blake2" @@ -25,21 +25,21 @@ DIGEST_SIZE :: 32 // hash_string will hash the given input and return the // computed hash hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) + return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2s_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2S_SIZE - ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE]byte + ctx: _blake2.Blake2s_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2S_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash[:]) + return hash } @@ -47,65 +47,65 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: _blake2.Blake2s_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2S_SIZE - ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash) + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: _blake2.Blake2s_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2S_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2s_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2S_SIZE - ctx.cfg = cfg - _blake2.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _blake2.update(&ctx, buf[:read]) - } - } - _blake2.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE]byte + ctx: _blake2.Blake2s_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2S_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _blake2.update(&ctx, buf[:read]) + } + } + _blake2.final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [DIGEST_SIZE]byte{}, false } hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, + hash_stream, + hash_file, + hash_bytes, + hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -115,13 +115,13 @@ hash :: proc { Blake2s_Context :: _blake2.Blake2b_Context init :: proc(ctx: ^_blake2.Blake2s_Context) { - _blake2.init(ctx) + _blake2.init(ctx) } update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) { - _blake2.update(ctx, data) + _blake2.update(ctx, data) } final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) { - _blake2.final(ctx, hash) + _blake2.final(ctx, hash) } From 9d627e453adb2d26bc133fdff6e180851ad8ab9c Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 11:13:42 +0900 Subject: [PATCH 066/160] core/crypto/md5: odinfmt (NFC) --- core/crypto/md5/md5.odin | 357 ++++++++++++++++++++------------------- 1 file changed, 179 insertions(+), 178 deletions(-) diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index 858480b04..0b04916dc 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -10,9 +10,9 @@ package md5 Implementation of the MD5 hashing algorithm, as defined in RFC 1321 */ +import "core:io" import "core:mem" import "core:os" -import "core:io" import "../util" @@ -25,77 +25,77 @@ DIGEST_SIZE :: 16 // hash_string will hash the given input and return the // computed hash hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) + return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: Md5_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE]byte + ctx: Md5_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_string_to_buffer will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: Md5_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Md5_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: Md5_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE]byte + ctx: Md5_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [DIGEST_SIZE]byte{}, false } hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, + hash_stream, + hash_file, + hash_bytes, + hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -103,76 +103,76 @@ hash :: proc { */ init :: proc(ctx: ^Md5_Context) { - ctx.state[0] = 0x67452301 - ctx.state[1] = 0xefcdab89 - ctx.state[2] = 0x98badcfe - ctx.state[3] = 0x10325476 + ctx.state[0] = 0x67452301 + ctx.state[1] = 0xefcdab89 + ctx.state[2] = 0x98badcfe + ctx.state[3] = 0x10325476 } update :: proc(ctx: ^Md5_Context, data: []byte) { - for i := 0; i < len(data); i += 1 { - ctx.data[ctx.datalen] = data[i] - ctx.datalen += 1 - if(ctx.datalen == BLOCK_SIZE) { - transform(ctx, ctx.data[:]) - ctx.bitlen += 512 - ctx.datalen = 0 - } - } + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if (ctx.datalen == BLOCK_SIZE) { + transform(ctx, ctx.data[:]) + ctx.bitlen += 512 + ctx.datalen = 0 + } + } } -final :: proc(ctx: ^Md5_Context, hash: []byte){ - i : u32 - i = ctx.datalen +final :: proc(ctx: ^Md5_Context, hash: []byte) { + i: u32 + i = ctx.datalen - if ctx.datalen < 56 { - ctx.data[i] = 0x80 - i += 1 - for i < 56 { - ctx.data[i] = 0x00 - i += 1 - } - } else if ctx.datalen >= 56 { - ctx.data[i] = 0x80 - i += 1 - for i < BLOCK_SIZE { - ctx.data[i] = 0x00 - i += 1 - } - transform(ctx, ctx.data[:]) - mem.set(&ctx.data, 0, 56) - } + if ctx.datalen < 56 { + ctx.data[i] = 0x80 + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 + } + } else if ctx.datalen >= 56 { + ctx.data[i] = 0x80 + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } + transform(ctx, ctx.data[:]) + mem.set(&ctx.data, 0, 56) + } - ctx.bitlen += u64(ctx.datalen * 8) - ctx.data[56] = byte(ctx.bitlen) - ctx.data[57] = byte(ctx.bitlen >> 8) - ctx.data[58] = byte(ctx.bitlen >> 16) - ctx.data[59] = byte(ctx.bitlen >> 24) - ctx.data[60] = byte(ctx.bitlen >> 32) - ctx.data[61] = byte(ctx.bitlen >> 40) - ctx.data[62] = byte(ctx.bitlen >> 48) - ctx.data[63] = byte(ctx.bitlen >> 56) - transform(ctx, ctx.data[:]) + ctx.bitlen += u64(ctx.datalen * 8) + ctx.data[56] = byte(ctx.bitlen) + ctx.data[57] = byte(ctx.bitlen >> 8) + ctx.data[58] = byte(ctx.bitlen >> 16) + ctx.data[59] = byte(ctx.bitlen >> 24) + ctx.data[60] = byte(ctx.bitlen >> 32) + ctx.data[61] = byte(ctx.bitlen >> 40) + ctx.data[62] = byte(ctx.bitlen >> 48) + ctx.data[63] = byte(ctx.bitlen >> 56) + transform(ctx, ctx.data[:]) - for i = 0; i < 4; i += 1 { - hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff - hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff - hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff - hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff - } + for i = 0; i < 4; i += 1 { + hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff + hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff + hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff + hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff + } } /* MD4 implementation */ -BLOCK_SIZE :: 64 +BLOCK_SIZE :: 64 Md5_Context :: struct { - data: [BLOCK_SIZE]byte, - state: [4]u32, - bitlen: u64, - datalen: u32, + data: [BLOCK_SIZE]byte, + state: [4]u32, + bitlen: u64, + datalen: u32, } /* @@ -181,105 +181,106 @@ Md5_Context :: struct { */ FF :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + ((b & c) | (~b & d)) + m + t, s) + return b + util.ROTL32(a + ((b & c) | (~b & d)) + m + t, s) } GG :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + ((b & d) | (c & ~d)) + m + t, s) + return b + util.ROTL32(a + ((b & d) | (c & ~d)) + m + t, s) } HH :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + (b ~ c ~ d) + m + t, s) + return b + util.ROTL32(a + (b ~ c ~ d) + m + t, s) } II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + (c ~ (b | ~d)) + m + t, s) + return b + util.ROTL32(a + (c ~ (b | ~d)) + m + t, s) } transform :: proc(ctx: ^Md5_Context, data: []byte) { - i, j: u32 - m: [DIGEST_SIZE]u32 + i, j: u32 + m: [DIGEST_SIZE]u32 - for i, j = 0, 0; i < DIGEST_SIZE; i+=1 { - m[i] = u32(data[j]) + u32(data[j + 1]) << 8 + u32(data[j + 2]) << 16 + u32(data[j + 3]) << 24 - j += 4 - } + for i, j = 0, 0; i < DIGEST_SIZE; i += 1 { + m[i] = + u32(data[j]) + u32(data[j + 1]) << 8 + u32(data[j + 2]) << 16 + u32(data[j + 3]) << 24 + j += 4 + } - a := ctx.state[0] - b := ctx.state[1] - c := ctx.state[2] - d := ctx.state[3] + a := ctx.state[0] + b := ctx.state[1] + c := ctx.state[2] + d := ctx.state[3] - a = FF(a, b, c, d, m[0], 7, 0xd76aa478) - d = FF(d, a, b, c, m[1], 12, 0xe8c7b756) - c = FF(c, d, a, b, m[2], 17, 0x242070db) - b = FF(b, c, d, a, m[3], 22, 0xc1bdceee) - a = FF(a, b, c, d, m[4], 7, 0xf57c0faf) - d = FF(d, a, b, c, m[5], 12, 0x4787c62a) - c = FF(c, d, a, b, m[6], 17, 0xa8304613) - b = FF(b, c, d, a, m[7], 22, 0xfd469501) - a = FF(a, b, c, d, m[8], 7, 0x698098d8) - d = FF(d, a, b, c, m[9], 12, 0x8b44f7af) - c = FF(c, d, a, b, m[10], 17, 0xffff5bb1) - b = FF(b, c, d, a, m[11], 22, 0x895cd7be) - a = FF(a, b, c, d, m[12], 7, 0x6b901122) - d = FF(d, a, b, c, m[13], 12, 0xfd987193) - c = FF(c, d, a, b, m[14], 17, 0xa679438e) - b = FF(b, c, d, a, m[15], 22, 0x49b40821) + a = FF(a, b, c, d, m[0], 7, 0xd76aa478) + d = FF(d, a, b, c, m[1], 12, 0xe8c7b756) + c = FF(c, d, a, b, m[2], 17, 0x242070db) + b = FF(b, c, d, a, m[3], 22, 0xc1bdceee) + a = FF(a, b, c, d, m[4], 7, 0xf57c0faf) + d = FF(d, a, b, c, m[5], 12, 0x4787c62a) + c = FF(c, d, a, b, m[6], 17, 0xa8304613) + b = FF(b, c, d, a, m[7], 22, 0xfd469501) + a = FF(a, b, c, d, m[8], 7, 0x698098d8) + d = FF(d, a, b, c, m[9], 12, 0x8b44f7af) + c = FF(c, d, a, b, m[10], 17, 0xffff5bb1) + b = FF(b, c, d, a, m[11], 22, 0x895cd7be) + a = FF(a, b, c, d, m[12], 7, 0x6b901122) + d = FF(d, a, b, c, m[13], 12, 0xfd987193) + c = FF(c, d, a, b, m[14], 17, 0xa679438e) + b = FF(b, c, d, a, m[15], 22, 0x49b40821) - a = GG(a, b, c, d, m[1], 5, 0xf61e2562) - d = GG(d, a, b, c, m[6], 9, 0xc040b340) - c = GG(c, d, a, b, m[11], 14, 0x265e5a51) - b = GG(b, c, d, a, m[0], 20, 0xe9b6c7aa) - a = GG(a, b, c, d, m[5], 5, 0xd62f105d) - d = GG(d, a, b, c, m[10], 9, 0x02441453) - c = GG(c, d, a, b, m[15], 14, 0xd8a1e681) - b = GG(b, c, d, a, m[4], 20, 0xe7d3fbc8) - a = GG(a, b, c, d, m[9], 5, 0x21e1cde6) - d = GG(d, a, b, c, m[14], 9, 0xc33707d6) - c = GG(c, d, a, b, m[3], 14, 0xf4d50d87) - b = GG(b, c, d, a, m[8], 20, 0x455a14ed) - a = GG(a, b, c, d, m[13], 5, 0xa9e3e905) - d = GG(d, a, b, c, m[2], 9, 0xfcefa3f8) - c = GG(c, d, a, b, m[7], 14, 0x676f02d9) - b = GG(b, c, d, a, m[12], 20, 0x8d2a4c8a) + a = GG(a, b, c, d, m[1], 5, 0xf61e2562) + d = GG(d, a, b, c, m[6], 9, 0xc040b340) + c = GG(c, d, a, b, m[11], 14, 0x265e5a51) + b = GG(b, c, d, a, m[0], 20, 0xe9b6c7aa) + a = GG(a, b, c, d, m[5], 5, 0xd62f105d) + d = GG(d, a, b, c, m[10], 9, 0x02441453) + c = GG(c, d, a, b, m[15], 14, 0xd8a1e681) + b = GG(b, c, d, a, m[4], 20, 0xe7d3fbc8) + a = GG(a, b, c, d, m[9], 5, 0x21e1cde6) + d = GG(d, a, b, c, m[14], 9, 0xc33707d6) + c = GG(c, d, a, b, m[3], 14, 0xf4d50d87) + b = GG(b, c, d, a, m[8], 20, 0x455a14ed) + a = GG(a, b, c, d, m[13], 5, 0xa9e3e905) + d = GG(d, a, b, c, m[2], 9, 0xfcefa3f8) + c = GG(c, d, a, b, m[7], 14, 0x676f02d9) + b = GG(b, c, d, a, m[12], 20, 0x8d2a4c8a) - a = HH(a, b, c, d, m[5], 4, 0xfffa3942) - d = HH(d, a, b, c, m[8], 11, 0x8771f681) - c = HH(c, d, a, b, m[11], 16, 0x6d9d6122) - b = HH(b, c, d, a, m[14], 23, 0xfde5380c) - a = HH(a, b, c, d, m[1], 4, 0xa4beea44) - d = HH(d, a, b, c, m[4], 11, 0x4bdecfa9) - c = HH(c, d, a, b, m[7], 16, 0xf6bb4b60) - b = HH(b, c, d, a, m[10], 23, 0xbebfbc70) - a = HH(a, b, c, d, m[13], 4, 0x289b7ec6) - d = HH(d, a, b, c, m[0], 11, 0xeaa127fa) - c = HH(c, d, a, b, m[3], 16, 0xd4ef3085) - b = HH(b, c, d, a, m[6], 23, 0x04881d05) - a = HH(a, b, c, d, m[9], 4, 0xd9d4d039) - d = HH(d, a, b, c, m[12], 11, 0xe6db99e5) - c = HH(c, d, a, b, m[15], 16, 0x1fa27cf8) - b = HH(b, c, d, a, m[2], 23, 0xc4ac5665) + a = HH(a, b, c, d, m[5], 4, 0xfffa3942) + d = HH(d, a, b, c, m[8], 11, 0x8771f681) + c = HH(c, d, a, b, m[11], 16, 0x6d9d6122) + b = HH(b, c, d, a, m[14], 23, 0xfde5380c) + a = HH(a, b, c, d, m[1], 4, 0xa4beea44) + d = HH(d, a, b, c, m[4], 11, 0x4bdecfa9) + c = HH(c, d, a, b, m[7], 16, 0xf6bb4b60) + b = HH(b, c, d, a, m[10], 23, 0xbebfbc70) + a = HH(a, b, c, d, m[13], 4, 0x289b7ec6) + d = HH(d, a, b, c, m[0], 11, 0xeaa127fa) + c = HH(c, d, a, b, m[3], 16, 0xd4ef3085) + b = HH(b, c, d, a, m[6], 23, 0x04881d05) + a = HH(a, b, c, d, m[9], 4, 0xd9d4d039) + d = HH(d, a, b, c, m[12], 11, 0xe6db99e5) + c = HH(c, d, a, b, m[15], 16, 0x1fa27cf8) + b = HH(b, c, d, a, m[2], 23, 0xc4ac5665) - a = II(a, b, c, d, m[0], 6, 0xf4292244) - d = II(d, a, b, c, m[7], 10, 0x432aff97) - c = II(c, d, a, b, m[14], 15, 0xab9423a7) - b = II(b, c, d, a, m[5], 21, 0xfc93a039) - a = II(a, b, c, d, m[12], 6, 0x655b59c3) - d = II(d, a, b, c, m[3], 10, 0x8f0ccc92) - c = II(c, d, a, b, m[10], 15, 0xffeff47d) - b = II(b, c, d, a, m[1], 21, 0x85845dd1) - a = II(a, b, c, d, m[8], 6, 0x6fa87e4f) - d = II(d, a, b, c, m[15], 10, 0xfe2ce6e0) - c = II(c, d, a, b, m[6], 15, 0xa3014314) - b = II(b, c, d, a, m[13], 21, 0x4e0811a1) - a = II(a, b, c, d, m[4], 6, 0xf7537e82) - d = II(d, a, b, c, m[11], 10, 0xbd3af235) - c = II(c, d, a, b, m[2], 15, 0x2ad7d2bb) - b = II(b, c, d, a, m[9], 21, 0xeb86d391) + a = II(a, b, c, d, m[0], 6, 0xf4292244) + d = II(d, a, b, c, m[7], 10, 0x432aff97) + c = II(c, d, a, b, m[14], 15, 0xab9423a7) + b = II(b, c, d, a, m[5], 21, 0xfc93a039) + a = II(a, b, c, d, m[12], 6, 0x655b59c3) + d = II(d, a, b, c, m[3], 10, 0x8f0ccc92) + c = II(c, d, a, b, m[10], 15, 0xffeff47d) + b = II(b, c, d, a, m[1], 21, 0x85845dd1) + a = II(a, b, c, d, m[8], 6, 0x6fa87e4f) + d = II(d, a, b, c, m[15], 10, 0xfe2ce6e0) + c = II(c, d, a, b, m[6], 15, 0xa3014314) + b = II(b, c, d, a, m[13], 21, 0x4e0811a1) + a = II(a, b, c, d, m[4], 6, 0xf7537e82) + d = II(d, a, b, c, m[11], 10, 0xbd3af235) + c = II(c, d, a, b, m[2], 15, 0x2ad7d2bb) + b = II(b, c, d, a, m[9], 21, 0xeb86d391) - ctx.state[0] += a - ctx.state[1] += b - ctx.state[2] += c - ctx.state[3] += d + ctx.state[0] += a + ctx.state[1] += b + ctx.state[2] += c + ctx.state[3] += d } From b4e3da84c5b0d2032efeda7da4d8d1a5cd58f283 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 11:26:24 +0900 Subject: [PATCH 067/160] core/crypto/sha1: odinfmt (NFC) --- core/crypto/sha1/sha1.odin | 154 ++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index 599d1791e..d868fca80 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -10,9 +10,9 @@ package sha1 Implementation of the SHA1 hashing algorithm, as defined in RFC 3174 */ +import "core:io" import "core:mem" import "core:os" -import "core:io" import "../util" @@ -25,77 +25,77 @@ DIGEST_SIZE :: 20 // hash_string will hash the given input and return the // computed hash hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) + return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: Sha1_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE]byte + ctx: Sha1_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_string_to_buffer will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: Sha1_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Sha1_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: Sha1_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE]byte + ctx: Sha1_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [DIGEST_SIZE]byte{}, false } hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, + hash_stream, + hash_file, + hash_bytes, + hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -108,10 +108,10 @@ init :: proc(ctx: ^Sha1_Context) { ctx.state[2] = 0x98badcfe ctx.state[3] = 0x10325476 ctx.state[4] = 0xc3d2e1f0 - ctx.k[0] = 0x5a827999 - ctx.k[1] = 0x6ed9eba1 - ctx.k[2] = 0x8f1bbcdc - ctx.k[3] = 0xca62c1d6 + ctx.k[0] = 0x5a827999 + ctx.k[1] = 0x6ed9eba1 + ctx.k[2] = 0x8f1bbcdc + ctx.k[3] = 0xca62c1d6 } update :: proc(ctx: ^Sha1_Context, data: []byte) { @@ -131,24 +131,23 @@ final :: proc(ctx: ^Sha1_Context, hash: []byte) { if ctx.datalen < 56 { ctx.data[i] = 0x80 - i += 1 - for i < 56 { - ctx.data[i] = 0x00 - i += 1 - } - } - else { + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 + } + } else { ctx.data[i] = 0x80 - i += 1 - for i < BLOCK_SIZE { - ctx.data[i] = 0x00 - i += 1 - } + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } transform(ctx, ctx.data[:]) mem.set(&ctx.data, 0, 56) } - ctx.bitlen += u64(ctx.datalen * 8) + ctx.bitlen += u64(ctx.datalen * 8) ctx.data[63] = u8(ctx.bitlen) ctx.data[62] = u8(ctx.bitlen >> 8) ctx.data[61] = u8(ctx.bitlen >> 16) @@ -160,9 +159,9 @@ final :: proc(ctx: ^Sha1_Context, hash: []byte) { transform(ctx, ctx.data[:]) for j: u32 = 0; j < 4; j += 1 { - hash[j] = u8(ctx.state[0] >> (24 - j * 8)) & 0x000000ff - hash[j + 4] = u8(ctx.state[1] >> (24 - j * 8)) & 0x000000ff - hash[j + 8] = u8(ctx.state[2] >> (24 - j * 8)) & 0x000000ff + hash[j] = u8(ctx.state[0] >> (24 - j * 8)) & 0x000000ff + hash[j + 4] = u8(ctx.state[1] >> (24 - j * 8)) & 0x000000ff + hash[j + 8] = u8(ctx.state[2] >> (24 - j * 8)) & 0x000000ff hash[j + 12] = u8(ctx.state[3] >> (24 - j * 8)) & 0x000000ff hash[j + 16] = u8(ctx.state[4] >> (24 - j * 8)) & 0x000000ff } @@ -172,28 +171,29 @@ final :: proc(ctx: ^Sha1_Context, hash: []byte) { SHA1 implementation */ -BLOCK_SIZE :: 64 +BLOCK_SIZE :: 64 Sha1_Context :: struct { - data: [BLOCK_SIZE]byte, - datalen: u32, - bitlen: u64, - state: [5]u32, - k: [4]u32, + data: [BLOCK_SIZE]byte, + datalen: u32, + bitlen: u64, + state: [5]u32, + k: [4]u32, } transform :: proc(ctx: ^Sha1_Context, data: []byte) { - a, b, c, d, e, i, j, t: u32 - m: [80]u32 + a, b, c, d, e, i, j, t: u32 + m: [80]u32 for i, j = 0, 0; i < 16; i += 1 { - m[i] = u32(data[j]) << 24 + u32(data[j + 1]) << 16 + u32(data[j + 2]) << 8 + u32(data[j + 3]) - j += 4 - } + m[i] = + u32(data[j]) << 24 + u32(data[j + 1]) << 16 + u32(data[j + 2]) << 8 + u32(data[j + 3]) + j += 4 + } for i < 80 { m[i] = (m[i - 3] ~ m[i - 8] ~ m[i - 14] ~ m[i - 16]) m[i] = (m[i] << 1) | (m[i] >> 31) - i += 1 + i += 1 } a = ctx.state[0] @@ -217,7 +217,7 @@ transform :: proc(ctx: ^Sha1_Context, data: []byte) { c = util.ROTL32(b, 30) b = a a = t - i += 1 + i += 1 } for i < 60 { t = util.ROTL32(a, 5) + ((b & c) ~ (b & d) ~ (c & d)) + e + ctx.k[2] + m[i] @@ -226,7 +226,7 @@ transform :: proc(ctx: ^Sha1_Context, data: []byte) { c = util.ROTL32(b, 30) b = a a = t - i += 1 + i += 1 } for i < 80 { t = util.ROTL32(a, 5) + (b ~ c ~ d) + e + ctx.k[3] + m[i] @@ -235,7 +235,7 @@ transform :: proc(ctx: ^Sha1_Context, data: []byte) { c = util.ROTL32(b, 30) b = a a = t - i += 1 + i += 1 } ctx.state[0] += a From 14a46c6d5efabf5be60c3c6e641f800916a558b1 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Wed, 15 Nov 2023 22:26:53 +0900 Subject: [PATCH 068/160] core/crypto/sha2: odinfmt (NFC) --- core/crypto/sha2/sha2.odin | 731 +++++++++++++++++++------------------ 1 file changed, 373 insertions(+), 358 deletions(-) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 0f55c4be1..4a12eef7e 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -11,9 +11,9 @@ package sha2 and in RFC 3874 */ +import "core:io" import "core:mem" import "core:os" -import "core:io" import "../util" @@ -29,317 +29,329 @@ DIGEST_SIZE_512 :: 64 // hash_string_224 will hash the given input and return the // computed hash hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224(transmute([]byte)(data)) + return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte + hash: [DIGEST_SIZE_224]byte ctx: Sha256_Context - ctx.is224 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash + ctx.is224 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_224 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash) + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: Sha256_Context - ctx.is224 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_224, + "Size of destination buffer is smaller than the digest size", + ) + ctx: Sha256_Context + ctx.is224 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { hash: [DIGEST_SIZE_224]byte - ctx: Sha512_Context - ctx.is384 = false - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { - hash_stream_224, - hash_file_224, - hash_bytes_224, - hash_string_224, - hash_bytes_to_buffer_224, - hash_string_to_buffer_224, + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) + return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte + hash: [DIGEST_SIZE_256]byte ctx: Sha256_Context - ctx.is224 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash + ctx.is224 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_256 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Sha256_Context - ctx.is224 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_256, + "Size of destination buffer is smaller than the digest size", + ) + ctx: Sha256_Context + ctx.is224 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: Sha512_Context - ctx.is384 = false - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { - return hash_bytes_384(transmute([]byte)(data)) + return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { - hash: [DIGEST_SIZE_384]byte + hash: [DIGEST_SIZE_384]byte ctx: Sha512_Context - ctx.is384 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash + ctx.is384 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_384 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash) + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: Sha512_Context - ctx.is384 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_384, + "Size of destination buffer is smaller than the digest size", + ) + ctx: Sha512_Context + ctx.is384 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { hash: [DIGEST_SIZE_384]byte - ctx: Sha512_Context - ctx.is384 = true - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true + ctx: Sha512_Context + ctx.is384 = true + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { - if !load_at_once { - return hash_stream_384(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_384(buf[:]), ok - } - } - return [DIGEST_SIZE_384]byte{}, false + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { - hash_stream_384, - hash_file_384, - hash_bytes_384, - hash_string_384, - hash_bytes_to_buffer_384, - hash_string_to_buffer_384, + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) + return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte + hash: [DIGEST_SIZE_512]byte ctx: Sha512_Context - ctx.is384 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash + ctx.is384 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_512 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: Sha512_Context - ctx.is384 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_512, + "Size of destination buffer is smaller than the digest size", + ) + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: Sha512_Context - ctx.is384 = false + hash: [DIGEST_SIZE_512]byte + ctx: Sha512_Context + ctx.is384 = false init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* @@ -347,122 +359,117 @@ hash_512 :: proc { */ init :: proc(ctx: ^$T) { - when T == Sha256_Context { - if ctx.is224 { - ctx.h[0] = 0xc1059ed8 - ctx.h[1] = 0x367cd507 - ctx.h[2] = 0x3070dd17 - ctx.h[3] = 0xf70e5939 - ctx.h[4] = 0xffc00b31 - ctx.h[5] = 0x68581511 - ctx.h[6] = 0x64f98fa7 - ctx.h[7] = 0xbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667 - ctx.h[1] = 0xbb67ae85 - ctx.h[2] = 0x3c6ef372 - ctx.h[3] = 0xa54ff53a - ctx.h[4] = 0x510e527f - ctx.h[5] = 0x9b05688c - ctx.h[6] = 0x1f83d9ab - ctx.h[7] = 0x5be0cd19 - } - } else when T == Sha512_Context { - if ctx.is384 { - ctx.h[0] = 0xcbbb9d5dc1059ed8 - ctx.h[1] = 0x629a292a367cd507 - ctx.h[2] = 0x9159015a3070dd17 - ctx.h[3] = 0x152fecd8f70e5939 - ctx.h[4] = 0x67332667ffc00b31 - ctx.h[5] = 0x8eb44a8768581511 - ctx.h[6] = 0xdb0c2e0d64f98fa7 - ctx.h[7] = 0x47b5481dbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667f3bcc908 - ctx.h[1] = 0xbb67ae8584caa73b - ctx.h[2] = 0x3c6ef372fe94f82b - ctx.h[3] = 0xa54ff53a5f1d36f1 - ctx.h[4] = 0x510e527fade682d1 - ctx.h[5] = 0x9b05688c2b3e6c1f - ctx.h[6] = 0x1f83d9abfb41bd6b - ctx.h[7] = 0x5be0cd19137e2179 - } - } + when T == Sha256_Context { + if ctx.is224 { + ctx.h[0] = 0xc1059ed8 + ctx.h[1] = 0x367cd507 + ctx.h[2] = 0x3070dd17 + ctx.h[3] = 0xf70e5939 + ctx.h[4] = 0xffc00b31 + ctx.h[5] = 0x68581511 + ctx.h[6] = 0x64f98fa7 + ctx.h[7] = 0xbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667 + ctx.h[1] = 0xbb67ae85 + ctx.h[2] = 0x3c6ef372 + ctx.h[3] = 0xa54ff53a + ctx.h[4] = 0x510e527f + ctx.h[5] = 0x9b05688c + ctx.h[6] = 0x1f83d9ab + ctx.h[7] = 0x5be0cd19 + } + } else when T == Sha512_Context { + if ctx.is384 { + ctx.h[0] = 0xcbbb9d5dc1059ed8 + ctx.h[1] = 0x629a292a367cd507 + ctx.h[2] = 0x9159015a3070dd17 + ctx.h[3] = 0x152fecd8f70e5939 + ctx.h[4] = 0x67332667ffc00b31 + ctx.h[5] = 0x8eb44a8768581511 + ctx.h[6] = 0xdb0c2e0d64f98fa7 + ctx.h[7] = 0x47b5481dbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667f3bcc908 + ctx.h[1] = 0xbb67ae8584caa73b + ctx.h[2] = 0x3c6ef372fe94f82b + ctx.h[3] = 0xa54ff53a5f1d36f1 + ctx.h[4] = 0x510e527fade682d1 + ctx.h[5] = 0x9b05688c2b3e6c1f + ctx.h[6] = 0x1f83d9abfb41bd6b + ctx.h[7] = 0x5be0cd19137e2179 + } + } } update :: proc(ctx: ^$T, data: []byte) { - length := uint(len(data)) - block_nb: uint - new_len, rem_len, tmp_len: uint - shifted_message := make([]byte, length) + length := uint(len(data)) + block_nb: uint + new_len, rem_len, tmp_len: uint + shifted_message := make([]byte, length) - when T == Sha256_Context { - CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE - } else when T == Sha512_Context { - CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE - } + when T == Sha256_Context { + CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE + } else when T == Sha512_Context { + CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE + } - tmp_len = CURR_BLOCK_SIZE - ctx.length - rem_len = length < tmp_len ? length : tmp_len - copy(ctx.block[ctx.length:], data[:rem_len]) + tmp_len = CURR_BLOCK_SIZE - ctx.length + rem_len = length < tmp_len ? length : tmp_len + copy(ctx.block[ctx.length:], data[:rem_len]) - if ctx.length + length < CURR_BLOCK_SIZE { - ctx.length += length - return - } + if ctx.length + length < CURR_BLOCK_SIZE { + ctx.length += length + return + } - new_len = length - rem_len - block_nb = new_len / CURR_BLOCK_SIZE - shifted_message = data[rem_len:] + new_len = length - rem_len + block_nb = new_len / CURR_BLOCK_SIZE + shifted_message = data[rem_len:] - sha2_transf(ctx, ctx.block[:], 1) - sha2_transf(ctx, shifted_message, block_nb) + sha2_transf(ctx, ctx.block[:], 1) + sha2_transf(ctx, shifted_message, block_nb) - rem_len = new_len % CURR_BLOCK_SIZE - if rem_len > 0 { - when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])} - else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])} - } + rem_len = new_len % CURR_BLOCK_SIZE + if rem_len > 0 { + when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])} else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])} + } - ctx.length = rem_len - when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6} - else when T == Sha512_Context {ctx.tot_len += (block_nb + 1) << 7} + ctx.length = rem_len + when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6} else when T == Sha512_Context {ctx.tot_len += (block_nb + 1) << 7} } final :: proc(ctx: ^$T, hash: []byte) { - block_nb, pm_len, len_b: u32 - i: i32 + block_nb, pm_len, len_b: u32 + i: i32 - when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} - else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} + when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} - when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} - else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} + when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} - len_b = u32(ctx.tot_len + ctx.length) << 3 - when T == Sha256_Context {pm_len = block_nb << 6} - else when T == Sha512_Context {pm_len = block_nb << 7} + len_b = u32(ctx.tot_len + ctx.length) << 3 + when T == Sha256_Context {pm_len = block_nb << 6} else when T == Sha512_Context {pm_len = block_nb << 7} - mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length)) - ctx.block[ctx.length] = 0x80 + mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length)) + ctx.block[ctx.length] = 0x80 - util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b) + util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b) - sha2_transf(ctx, ctx.block[:], uint(block_nb)) + sha2_transf(ctx, ctx.block[:], uint(block_nb)) - when T == Sha256_Context { - if ctx.is224 { - for i = 0; i < 7; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} - } else { - for i = 0; i < 8; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} - } - } else when T == Sha512_Context { - if ctx.is384 { - for i = 0; i < 6; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} - } else { - for i = 0; i < 8; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} - } - } + when T == Sha256_Context { + if ctx.is224 { + for i = 0; i < 7; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + } else { + for i = 0; i < 8; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + } + } else when T == Sha512_Context { + if ctx.is384 { + for i = 0; i < 6; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + } else { + for i = 0; i < 8; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + } + } } /* @@ -473,137 +480,145 @@ SHA256_BLOCK_SIZE :: 64 SHA512_BLOCK_SIZE :: 128 Sha256_Context :: struct { - tot_len: uint, - length: uint, - block: [128]byte, - h: [8]u32, - is224: bool, + tot_len: uint, + length: uint, + block: [128]byte, + h: [8]u32, + is224: bool, } Sha512_Context :: struct { - tot_len: uint, - length: uint, - block: [256]byte, - h: [8]u64, - is384: bool, + tot_len: uint, + length: uint, + block: [256]byte, + h: [8]u64, + is384: bool, } sha256_k := [64]u32 { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, } sha512_k := [80]u64 { - 0x428a2f98d728ae22, 0x7137449123ef65cd, - 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, - 0x3956c25bf348b538, 0x59f111f1b605d019, - 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, - 0xd807aa98a3030242, 0x12835b0145706fbe, - 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, - 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, - 0x9bdc06a725c71235, 0xc19bf174cf692694, - 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, - 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, - 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, - 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, - 0x983e5152ee66dfab, 0xa831c66d2db43210, - 0xb00327c898fb213f, 0xbf597fc7beef0ee4, - 0xc6e00bf33da88fc2, 0xd5a79147930aa725, - 0x06ca6351e003826f, 0x142929670a0e6e70, - 0x27b70a8546d22ffc, 0x2e1b21385c26c926, - 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, - 0x650a73548baf63de, 0x766a0abb3c77b2a8, - 0x81c2c92e47edaee6, 0x92722c851482353b, - 0xa2bfe8a14cf10364, 0xa81a664bbc423001, - 0xc24b8b70d0f89791, 0xc76c51a30654be30, - 0xd192e819d6ef5218, 0xd69906245565a910, - 0xf40e35855771202a, 0x106aa07032bbd1b8, - 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, - 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, - 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, - 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, - 0x748f82ee5defb2fc, 0x78a5636f43172f60, - 0x84c87814a1f0ab72, 0x8cc702081a6439ec, - 0x90befffa23631e28, 0xa4506cebde82bde9, - 0xbef9a3f7b2c67915, 0xc67178f2e372532b, - 0xca273eceea26619c, 0xd186b8c721c0c207, - 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, - 0x06f067aa72176fba, 0x0a637dc5a2c898a6, - 0x113f9804bef90dae, 0x1b710b35131c471b, - 0x28db77f523047d84, 0x32caab7b40c72493, - 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, - 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, - 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, + 0x428a2f98d728ae22, 0x7137449123ef65cd, + 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, + 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, + 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, + 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, + 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, + 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, + 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, + 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, + 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, + 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, + 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, + 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, } -SHA256_CH :: #force_inline proc "contextless"(x, y, z: u32) -> u32 { - return (x & y) ~ (~x & z) +SHA256_CH :: #force_inline proc "contextless" (x, y, z: u32) -> u32 { + return (x & y) ~ (~x & z) } -SHA256_MAJ :: #force_inline proc "contextless"(x, y, z: u32) -> u32 { - return (x & y) ~ (x & z) ~ (y & z) +SHA256_MAJ :: #force_inline proc "contextless" (x, y, z: u32) -> u32 { + return (x & y) ~ (x & z) ~ (y & z) } -SHA512_CH :: #force_inline proc "contextless"(x, y, z: u64) -> u64 { - return (x & y) ~ (~x & z) +SHA512_CH :: #force_inline proc "contextless" (x, y, z: u64) -> u64 { + return (x & y) ~ (~x & z) } -SHA512_MAJ :: #force_inline proc "contextless"(x, y, z: u64) -> u64 { - return (x & y) ~ (x & z) ~ (y & z) +SHA512_MAJ :: #force_inline proc "contextless" (x, y, z: u64) -> u64 { + return (x & y) ~ (x & z) ~ (y & z) } -SHA256_F1 :: #force_inline proc "contextless"(x: u32) -> u32 { - return util.ROTR32(x, 2) ~ util.ROTR32(x, 13) ~ util.ROTR32(x, 22) +SHA256_F1 :: #force_inline proc "contextless" (x: u32) -> u32 { + return util.ROTR32(x, 2) ~ util.ROTR32(x, 13) ~ util.ROTR32(x, 22) } -SHA256_F2 :: #force_inline proc "contextless"(x: u32) -> u32 { - return util.ROTR32(x, 6) ~ util.ROTR32(x, 11) ~ util.ROTR32(x, 25) +SHA256_F2 :: #force_inline proc "contextless" (x: u32) -> u32 { + return util.ROTR32(x, 6) ~ util.ROTR32(x, 11) ~ util.ROTR32(x, 25) } -SHA256_F3 :: #force_inline proc "contextless"(x: u32) -> u32 { - return util.ROTR32(x, 7) ~ util.ROTR32(x, 18) ~ (x >> 3) +SHA256_F3 :: #force_inline proc "contextless" (x: u32) -> u32 { + return util.ROTR32(x, 7) ~ util.ROTR32(x, 18) ~ (x >> 3) } -SHA256_F4 :: #force_inline proc "contextless"(x: u32) -> u32 { - return util.ROTR32(x, 17) ~ util.ROTR32(x, 19) ~ (x >> 10) +SHA256_F4 :: #force_inline proc "contextless" (x: u32) -> u32 { + return util.ROTR32(x, 17) ~ util.ROTR32(x, 19) ~ (x >> 10) } -SHA512_F1 :: #force_inline proc "contextless"(x: u64) -> u64 { - return util.ROTR64(x, 28) ~ util.ROTR64(x, 34) ~ util.ROTR64(x, 39) +SHA512_F1 :: #force_inline proc "contextless" (x: u64) -> u64 { + return util.ROTR64(x, 28) ~ util.ROTR64(x, 34) ~ util.ROTR64(x, 39) } -SHA512_F2 :: #force_inline proc "contextless"(x: u64) -> u64 { - return util.ROTR64(x, 14) ~ util.ROTR64(x, 18) ~ util.ROTR64(x, 41) +SHA512_F2 :: #force_inline proc "contextless" (x: u64) -> u64 { + return util.ROTR64(x, 14) ~ util.ROTR64(x, 18) ~ util.ROTR64(x, 41) } -SHA512_F3 :: #force_inline proc "contextless"(x: u64) -> u64 { - return util.ROTR64(x, 1) ~ util.ROTR64(x, 8) ~ (x >> 7) +SHA512_F3 :: #force_inline proc "contextless" (x: u64) -> u64 { + return util.ROTR64(x, 1) ~ util.ROTR64(x, 8) ~ (x >> 7) } -SHA512_F4 :: #force_inline proc "contextless"(x: u64) -> u64 { - return util.ROTR64(x, 19) ~ util.ROTR64(x, 61) ~ (x >> 6) +SHA512_F4 :: #force_inline proc "contextless" (x: u64) -> u64 { + return util.ROTR64(x, 19) ~ util.ROTR64(x, 61) ~ (x >> 6) } -PACK32 :: #force_inline proc "contextless"(b: []byte, x: ^u32) { +PACK32 :: #force_inline proc "contextless" (b: []byte, x: ^u32) { x^ = u32(b[3]) | u32(b[2]) << 8 | u32(b[1]) << 16 | u32(b[0]) << 24 } -PACK64 :: #force_inline proc "contextless"(b: []byte, x: ^u64) { - x^ = u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 +PACK64 :: #force_inline proc "contextless" (b: []byte, x: ^u64) { + x^ = + u64(b[7]) | + u64(b[6]) << 8 | + u64(b[5]) << 16 | + u64(b[4]) << 24 | + u64(b[3]) << 32 | + u64(b[2]) << 40 | + u64(b[1]) << 48 | + u64(b[0]) << 56 } sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { From d50380709d565f67e57e3551afb413c2edc57e2e Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 00:18:59 +0900 Subject: [PATCH 069/160] core/crypto/sha3: odinfmt (NFC) --- core/crypto/_sha3/sha3.odin | 249 +++++++++++---------- core/crypto/keccak/keccak.odin | 398 +++++++++++++++++---------------- core/crypto/sha3/sha3.odin | 372 +++++++++++++++--------------- core/crypto/shake/shake.odin | 204 +++++++++-------- 4 files changed, 629 insertions(+), 594 deletions(-) diff --git a/core/crypto/_sha3/sha3.odin b/core/crypto/_sha3/sha3.odin index 9846aca42..a56dce097 100644 --- a/core/crypto/_sha3/sha3.odin +++ b/core/crypto/_sha3/sha3.odin @@ -16,154 +16,159 @@ import "../util" ROUNDS :: 24 Sha3_Context :: struct { - st: struct #raw_union { - b: [200]u8, - q: [25]u64, - }, - pt: int, - rsiz: int, - mdlen: int, - is_keccak: bool, + st: struct #raw_union { + b: [200]u8, + q: [25]u64, + }, + pt: int, + rsiz: int, + mdlen: int, + is_keccak: bool, } keccakf :: proc "contextless" (st: ^[25]u64) { - keccakf_rndc := [?]u64 { - 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, - 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, - 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, - 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, - 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, - 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, - 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, - } + keccakf_rndc := [?]u64 { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, + } - keccakf_rotc := [?]i32 { - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, - } + keccakf_rotc := [?]i32 { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, + } - keccakf_piln := [?]i32 { - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, - } + keccakf_piln := [?]i32 { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, + } - i, j, r: i32 = ---, ---, --- - t: u64 = --- - bc: [5]u64 = --- + i, j, r: i32 = ---, ---, --- + t: u64 = --- + bc: [5]u64 = --- - when ODIN_ENDIAN != .Little { - v: uintptr = --- - for i = 0; i < 25; i += 1 { - v := uintptr(&st[i]) - st[i] = u64((^u8)(v + 0)^ << 0) | u64((^u8)(v + 1)^ << 8) | - u64((^u8)(v + 2)^ << 16) | u64((^u8)(v + 3)^ << 24) | - u64((^u8)(v + 4)^ << 32) | u64((^u8)(v + 5)^ << 40) | - u64((^u8)(v + 6)^ << 48) | u64((^u8)(v + 7)^ << 56) - } - } + when ODIN_ENDIAN != .Little { + v: uintptr = --- + for i = 0; i < 25; i += 1 { + v := uintptr(&st[i]) + st[i] = + u64((^u8)(v + 0)^ << 0) | + u64((^u8)(v + 1)^ << 8) | + u64((^u8)(v + 2)^ << 16) | + u64((^u8)(v + 3)^ << 24) | + u64((^u8)(v + 4)^ << 32) | + u64((^u8)(v + 5)^ << 40) | + u64((^u8)(v + 6)^ << 48) | + u64((^u8)(v + 7)^ << 56) + } + } - for r = 0; r < ROUNDS; r += 1 { - // theta - for i = 0; i < 5; i += 1 { - bc[i] = st[i] ~ st[i + 5] ~ st[i + 10] ~ st[i + 15] ~ st[i + 20] - } + for r = 0; r < ROUNDS; r += 1 { + // theta + for i = 0; i < 5; i += 1 { + bc[i] = st[i] ~ st[i + 5] ~ st[i + 10] ~ st[i + 15] ~ st[i + 20] + } - for i = 0; i < 5; i += 1 { - t = bc[(i + 4) % 5] ~ util.ROTL64(bc[(i + 1) % 5], 1) - for j = 0; j < 25; j += 5 { - st[j + i] ~= t - } - } + for i = 0; i < 5; i += 1 { + t = bc[(i + 4) % 5] ~ util.ROTL64(bc[(i + 1) % 5], 1) + for j = 0; j < 25; j += 5 { + st[j + i] ~= t + } + } - // rho pi - t = st[1] - for i = 0; i < 24; i += 1 { - j = keccakf_piln[i] - bc[0] = st[j] - st[j] = util.ROTL64(t, u64(keccakf_rotc[i])) - t = bc[0] - } + // rho pi + t = st[1] + for i = 0; i < 24; i += 1 { + j = keccakf_piln[i] + bc[0] = st[j] + st[j] = util.ROTL64(t, u64(keccakf_rotc[i])) + t = bc[0] + } - // chi - for j = 0; j < 25; j += 5 { - for i = 0; i < 5; i += 1 { - bc[i] = st[j + i] - } - for i = 0; i < 5; i += 1 { - st[j + i] ~= ~bc[(i + 1) % 5] & bc[(i + 2) % 5] - } - } + // chi + for j = 0; j < 25; j += 5 { + for i = 0; i < 5; i += 1 { + bc[i] = st[j + i] + } + for i = 0; i < 5; i += 1 { + st[j + i] ~= ~bc[(i + 1) % 5] & bc[(i + 2) % 5] + } + } - st[0] ~= keccakf_rndc[r] - } + st[0] ~= keccakf_rndc[r] + } - when ODIN_ENDIAN != .Little { - for i = 0; i < 25; i += 1 { - v = uintptr(&st[i]) - t = st[i] - (^u8)(v + 0)^ = (t >> 0) & 0xff - (^u8)(v + 1)^ = (t >> 8) & 0xff - (^u8)(v + 2)^ = (t >> 16) & 0xff - (^u8)(v + 3)^ = (t >> 24) & 0xff - (^u8)(v + 4)^ = (t >> 32) & 0xff - (^u8)(v + 5)^ = (t >> 40) & 0xff - (^u8)(v + 6)^ = (t >> 48) & 0xff - (^u8)(v + 7)^ = (t >> 56) & 0xff - } - } + when ODIN_ENDIAN != .Little { + for i = 0; i < 25; i += 1 { + v = uintptr(&st[i]) + t = st[i] + (^u8)(v + 0)^ = (t >> 0) & 0xff + (^u8)(v + 1)^ = (t >> 8) & 0xff + (^u8)(v + 2)^ = (t >> 16) & 0xff + (^u8)(v + 3)^ = (t >> 24) & 0xff + (^u8)(v + 4)^ = (t >> 32) & 0xff + (^u8)(v + 5)^ = (t >> 40) & 0xff + (^u8)(v + 6)^ = (t >> 48) & 0xff + (^u8)(v + 7)^ = (t >> 56) & 0xff + } + } } init :: proc "contextless" (c: ^Sha3_Context) { - for i := 0; i < 25; i += 1 { - c.st.q[i] = 0 - } - c.rsiz = 200 - 2 * c.mdlen + for i := 0; i < 25; i += 1 { + c.st.q[i] = 0 + } + c.rsiz = 200 - 2 * c.mdlen } update :: proc "contextless" (c: ^Sha3_Context, data: []byte) { - j := c.pt - for i := 0; i < len(data); i += 1 { - c.st.b[j] ~= data[i] - j += 1 - if j >= c.rsiz { - keccakf(&c.st.q) - j = 0 - } - } - c.pt = j + j := c.pt + for i := 0; i < len(data); i += 1 { + c.st.b[j] ~= data[i] + j += 1 + if j >= c.rsiz { + keccakf(&c.st.q) + j = 0 + } + } + c.pt = j } final :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { - if c.is_keccak { - c.st.b[c.pt] ~= 0x01 - } else { - c.st.b[c.pt] ~= 0x06 - } - - c.st.b[c.rsiz - 1] ~= 0x80 - keccakf(&c.st.q) - for i := 0; i < c.mdlen; i += 1 { - hash[i] = c.st.b[i] - } + if c.is_keccak { + c.st.b[c.pt] ~= 0x01 + } else { + c.st.b[c.pt] ~= 0x06 + } + + c.st.b[c.rsiz - 1] ~= 0x80 + keccakf(&c.st.q) + for i := 0; i < c.mdlen; i += 1 { + hash[i] = c.st.b[i] + } } shake_xof :: proc "contextless" (c: ^Sha3_Context) { - c.st.b[c.pt] ~= 0x1F - c.st.b[c.rsiz - 1] ~= 0x80 - keccakf(&c.st.q) - c.pt = 0 + c.st.b[c.pt] ~= 0x1F + c.st.b[c.rsiz - 1] ~= 0x80 + keccakf(&c.st.q) + c.pt = 0 } shake_out :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { - j := c.pt - for i := 0; i < len(hash); i += 1 { - if j >= c.rsiz { - keccakf(&c.st.q) - j = 0 - } - hash[i] = c.st.b[j] - j += 1 - } - c.pt = j + j := c.pt + for i := 0; i < len(hash); i += 1 { + if j >= c.rsiz { + keccakf(&c.st.q) + j = 0 + } + hash[i] = c.st.b[j] + j += 1 + } + c.pt = j } diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index 4c74858d2..fc9131fa3 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -11,8 +11,8 @@ package keccak This is done because the padding in the SHA3 standard was changed by the NIST, resulting in a different output. */ -import "core:os" import "core:io" +import "core:os" import "../_sha3" @@ -29,329 +29,341 @@ DIGEST_SIZE_512 :: 64 // hash_string_224 will hash the given input and return the // computed hash hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224(transmute([]byte)(data)) + return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_224 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_224]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_224 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash) + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_224 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_224, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_224 - ctx.is_keccak = true - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_224]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { - hash_stream_224, - hash_file_224, - hash_bytes_224, - hash_string_224, - hash_bytes_to_buffer_224, - hash_string_to_buffer_224, + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) + return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_256]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_256 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_256, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - ctx.is_keccak = true - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_256]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { - return hash_bytes_384(transmute([]byte)(data)) + return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { - hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_384 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_384]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_384 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash) + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_384 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_384, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { - hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_384 - ctx.is_keccak = true - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_384]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { - if !load_at_once { - return hash_stream_384(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_384(buf[:]), ok - } - } - return [DIGEST_SIZE_384]byte{}, false + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { - hash_stream_384, - hash_file_384, - hash_bytes_384, - hash_string_384, - hash_bytes_to_buffer_384, - hash_string_to_buffer_384, + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) + return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_512 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_512]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_512 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_512 - ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_512, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_512 - ctx.is_keccak = true - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_512]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* @@ -361,14 +373,14 @@ hash_512 :: proc { Keccak_Context :: _sha3.Sha3_Context init :: proc(ctx: ^_sha3.Sha3_Context) { - ctx.is_keccak = true - _sha3.init(ctx) + ctx.is_keccak = true + _sha3.init(ctx) } update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { - _sha3.update(ctx, data) + _sha3.update(ctx, data) } final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { - _sha3.final(ctx, hash) + _sha3.final(ctx, hash) } diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 5d8ad2106..6b7ad04a1 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -11,8 +11,8 @@ package sha3 If you wish to compute a Keccak hash, you can use the keccak package, it will use the original padding. */ -import "core:os" import "core:io" +import "core:os" import "../_sha3" @@ -28,317 +28,329 @@ DIGEST_SIZE_512 :: 64 // hash_string_224 will hash the given input and return the // computed hash hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224(transmute([]byte)(data)) + return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_224 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_224]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_224 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash) + hash_bytes_to_buffer_224(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_224 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_224 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_224, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_224 - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_224]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { - hash_stream_224, - hash_file_224, - hash_bytes_224, - hash_string_224, - hash_bytes_to_buffer_224, - hash_string_to_buffer_224, + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) + return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_256]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_256 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_256, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_256]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { - return hash_bytes_384(transmute([]byte)(data)) + return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { - hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_384 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_384]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_384 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash) + hash_bytes_to_buffer_384(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_384 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_384 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_384, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { - hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_384 - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_384]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { - if !load_at_once { - return hash_stream_384(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_384(buf[:]), ok - } - } - return [DIGEST_SIZE_384]byte{}, false + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { - hash_stream_384, - hash_file_384, - hash_bytes_384, - hash_string_384, - hash_bytes_to_buffer_384, - hash_string_to_buffer_384, + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) + return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_512 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_512]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_string_to_buffer_512 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) + hash_bytes_to_buffer_512(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_512 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_512 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_512, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_512 - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_512]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* @@ -348,13 +360,13 @@ hash_512 :: proc { Sha3_Context :: _sha3.Sha3_Context init :: proc(ctx: ^_sha3.Sha3_Context) { - _sha3.init(ctx) + _sha3.init(ctx) } update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { - _sha3.update(ctx, data) + _sha3.update(ctx, data) } final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { - _sha3.final(ctx, hash) + _sha3.final(ctx, hash) } diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 020ba68f3..70755069a 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -11,8 +11,8 @@ package shake The SHA3 functionality can be found in package sha3. */ -import "core:os" import "core:io" +import "core:os" import "../_sha3" @@ -26,165 +26,171 @@ DIGEST_SIZE_256 :: 32 // hash_string_128 will hash the given input and return the // computed hash hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128(transmute([]byte)(data)) + return hash_bytes_128(transmute([]byte)(data)) } // hash_bytes_128 will hash the given input and return the // computed hash hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_128 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_128]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_128 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash } // hash_string_to_buffer_128 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash) + hash_bytes_to_buffer_128(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_128 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_128 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_128, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_128 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash) } // hash_stream_128 will read the stream in chunks and compute a // hash from its contents hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_128 - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_128]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_128 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash, true } // hash_file_128 will read the file provided by the given handle // and compute a hash hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false + if !load_at_once { + return hash_stream_128(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128(buf[:]), ok + } + } + return [DIGEST_SIZE_128]byte{}, false } hash_128 :: proc { - hash_stream_128, - hash_file_128, - hash_bytes_128, - hash_string_128, - hash_bytes_to_buffer_128, - hash_string_to_buffer_128, + hash_stream_128, + hash_file_128, + hash_bytes_128, + hash_string_128, + hash_bytes_to_buffer_128, + hash_string_to_buffer_128, } // hash_string_256 will hash the given input and return the // computed hash hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) + return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE_256]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash } // hash_string_to_buffer_256 will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) + hash_bytes_to_buffer_256(transmute([]byte)(data), hash) } // hash_bytes_to_buffer_256 will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash) + assert( + len(hash) >= DIGEST_SIZE_256, + "Size of destination buffer is smaller than the digest size", + ) + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context - ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _sha3.update(&ctx, buf[:read]) - } - } - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE_256]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } /* @@ -194,14 +200,14 @@ hash_256 :: proc { Shake_Context :: _sha3.Sha3_Context init :: proc(ctx: ^_sha3.Sha3_Context) { - _sha3.init(ctx) + _sha3.init(ctx) } update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { - _sha3.update(ctx, data) + _sha3.update(ctx, data) } final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { - _sha3.shake_xof(ctx) - _sha3.shake_out(ctx, hash[:]) + _sha3.shake_xof(ctx) + _sha3.shake_out(ctx, hash[:]) } From 391b3090c9e1fb6e39493c7675c6dc088625121b Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 10:00:22 +0900 Subject: [PATCH 070/160] core/crypto/siphash: odinfmt (NFC) --- core/crypto/siphash/siphash.odin | 363 ++++++++++++++++--------------- 1 file changed, 188 insertions(+), 175 deletions(-) diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin index 2d03829c2..ef0c68ad3 100644 --- a/core/crypto/siphash/siphash.odin +++ b/core/crypto/siphash/siphash.odin @@ -19,196 +19,205 @@ import "core:crypto/util" High level API */ -KEY_SIZE :: 16 +KEY_SIZE :: 16 DIGEST_SIZE :: 8 // sum_string_1_3 will hash the given message with the key and return // the computed hash as a u64 sum_string_1_3 :: proc(msg, key: string) -> u64 { - return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key)) + return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key)) } // sum_bytes_1_3 will hash the given message with the key and return // the computed hash as a u64 -sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 { - ctx: Context - hash: u64 - init(&ctx, key, 1, 3) - update(&ctx, msg) - final(&ctx, &hash) - return hash +sum_bytes_1_3 :: proc(msg, key: []byte) -> u64 { + ctx: Context + hash: u64 + init(&ctx, key, 1, 3) + update(&ctx, msg) + final(&ctx, &hash) + return hash } // sum_string_to_buffer_1_3 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) { - sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst) + sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst) } // sum_bytes_to_buffer_1_3 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) { - assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8") - hash := sum_bytes_1_3(msg, key) - _collect_output(dst[:], hash) + assert( + len(dst) >= DIGEST_SIZE, + "crypto/siphash: Destination buffer needs to be at least of size 8", + ) + hash := sum_bytes_1_3(msg, key) + _collect_output(dst[:], hash) } sum_1_3 :: proc { - sum_string_1_3, - sum_bytes_1_3, - sum_string_to_buffer_1_3, - sum_bytes_to_buffer_1_3, + sum_string_1_3, + sum_bytes_1_3, + sum_string_to_buffer_1_3, + sum_bytes_to_buffer_1_3, } -// verify_u64_1_3 will check if the supplied tag matches with the output you +// verify_u64_1_3 will check if the supplied tag matches with the output you // will get from the provided message and key -verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool { - return sum_bytes_1_3(msg, key) == tag +verify_u64_1_3 :: proc(tag: u64, msg, key: []byte) -> bool { + return sum_bytes_1_3(msg, key) == tag } -// verify_bytes will check if the supplied tag matches with the output you +// verify_bytes will check if the supplied tag matches with the output you // will get from the provided message and key -verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool { - derived_tag: [8]byte - sum_bytes_to_buffer_1_3(msg, key, derived_tag[:]) - return crypto.compare_constant_time(derived_tag[:], tag) == 1 +verify_bytes_1_3 :: proc(tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_1_3(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 } verify_1_3 :: proc { - verify_bytes_1_3, - verify_u64_1_3, + verify_bytes_1_3, + verify_u64_1_3, } // sum_string_2_4 will hash the given message with the key and return // the computed hash as a u64 sum_string_2_4 :: proc(msg, key: string) -> u64 { - return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key)) + return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key)) } // sum_bytes_2_4 will hash the given message with the key and return // the computed hash as a u64 -sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 { - ctx: Context - hash: u64 - init(&ctx, key, 2, 4) - update(&ctx, msg) - final(&ctx, &hash) - return hash +sum_bytes_2_4 :: proc(msg, key: []byte) -> u64 { + ctx: Context + hash: u64 + init(&ctx, key, 2, 4) + update(&ctx, msg) + final(&ctx, &hash) + return hash } // sum_string_to_buffer_2_4 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) { - sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst) + sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst) } // sum_bytes_to_buffer_2_4 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) { - assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8") - hash := sum_bytes_2_4(msg, key) - _collect_output(dst[:], hash) + assert( + len(dst) >= DIGEST_SIZE, + "crypto/siphash: Destination buffer needs to be at least of size 8", + ) + hash := sum_bytes_2_4(msg, key) + _collect_output(dst[:], hash) } sum_2_4 :: proc { - sum_string_2_4, - sum_bytes_2_4, - sum_string_to_buffer_2_4, - sum_bytes_to_buffer_2_4, + sum_string_2_4, + sum_bytes_2_4, + sum_string_to_buffer_2_4, + sum_bytes_to_buffer_2_4, } -sum_string :: sum_string_2_4 -sum_bytes :: sum_bytes_2_4 +sum_string :: sum_string_2_4 +sum_bytes :: sum_bytes_2_4 sum_string_to_buffer :: sum_string_to_buffer_2_4 -sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4 +sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4 sum :: proc { - sum_string, - sum_bytes, - sum_string_to_buffer, - sum_bytes_to_buffer, + sum_string, + sum_bytes, + sum_string_to_buffer, + sum_bytes_to_buffer, } -// verify_u64_2_4 will check if the supplied tag matches with the output you +// verify_u64_2_4 will check if the supplied tag matches with the output you // will get from the provided message and key -verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool { - return sum_bytes_2_4(msg, key) == tag +verify_u64_2_4 :: proc(tag: u64, msg, key: []byte) -> bool { + return sum_bytes_2_4(msg, key) == tag } -// verify_bytes will check if the supplied tag matches with the output you +// verify_bytes will check if the supplied tag matches with the output you // will get from the provided message and key -verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool { - derived_tag: [8]byte - sum_bytes_to_buffer_2_4(msg, key, derived_tag[:]) - return crypto.compare_constant_time(derived_tag[:], tag) == 1 +verify_bytes_2_4 :: proc(tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_2_4(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 } verify_2_4 :: proc { - verify_bytes_2_4, - verify_u64_2_4, + verify_bytes_2_4, + verify_u64_2_4, } verify_bytes :: verify_bytes_2_4 -verify_u64 :: verify_u64_2_4 +verify_u64 :: verify_u64_2_4 verify :: proc { - verify_bytes, - verify_u64, + verify_bytes, + verify_u64, } // sum_string_4_8 will hash the given message with the key and return // the computed hash as a u64 sum_string_4_8 :: proc(msg, key: string) -> u64 { - return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key)) + return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key)) } // sum_bytes_4_8 will hash the given message with the key and return // the computed hash as a u64 -sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 { - ctx: Context - hash: u64 - init(&ctx, key, 4, 8) - update(&ctx, msg) - final(&ctx, &hash) - return hash +sum_bytes_4_8 :: proc(msg, key: []byte) -> u64 { + ctx: Context + hash: u64 + init(&ctx, key, 4, 8) + update(&ctx, msg) + final(&ctx, &hash) + return hash } // sum_string_to_buffer_4_8 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) { - sum_bytes_to_buffer_4_8(transmute([]byte)(msg), transmute([]byte)(key), dst) + sum_bytes_to_buffer_4_8(transmute([]byte)(msg), transmute([]byte)(key), dst) } // sum_bytes_to_buffer_4_8 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) { - assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8") - hash := sum_bytes_4_8(msg, key) - _collect_output(dst[:], hash) + assert( + len(dst) >= DIGEST_SIZE, + "crypto/siphash: Destination buffer needs to be at least of size 8", + ) + hash := sum_bytes_4_8(msg, key) + _collect_output(dst[:], hash) } sum_4_8 :: proc { - sum_string_4_8, - sum_bytes_4_8, - sum_string_to_buffer_4_8, - sum_bytes_to_buffer_4_8, + sum_string_4_8, + sum_bytes_4_8, + sum_string_to_buffer_4_8, + sum_bytes_to_buffer_4_8, } -// verify_u64_4_8 will check if the supplied tag matches with the output you +// verify_u64_4_8 will check if the supplied tag matches with the output you // will get from the provided message and key -verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool { - return sum_bytes_4_8(msg, key) == tag +verify_u64_4_8 :: proc(tag: u64, msg, key: []byte) -> bool { + return sum_bytes_4_8(msg, key) == tag } -// verify_bytes will check if the supplied tag matches with the output you +// verify_bytes will check if the supplied tag matches with the output you // will get from the provided message and key -verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool { - derived_tag: [8]byte - sum_bytes_to_buffer_4_8(msg, key, derived_tag[:]) - return crypto.compare_constant_time(derived_tag[:], tag) == 1 +verify_bytes_4_8 :: proc(tag, msg, key: []byte) -> bool { + derived_tag: [8]byte + sum_bytes_to_buffer_4_8(msg, key, derived_tag[:]) + return crypto.compare_constant_time(derived_tag[:], tag) == 1 } verify_4_8 :: proc { - verify_bytes_4_8, - verify_u64_4_8, + verify_bytes_4_8, + verify_u64_4_8, } /* @@ -216,120 +225,124 @@ verify_4_8 :: proc { */ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) { - assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16") - ctx.c_rounds = c_rounds - ctx.d_rounds = d_rounds - is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) || - (ctx.c_rounds == 2 && ctx.d_rounds == 4) || - (ctx.c_rounds == 4 && ctx.d_rounds == 8) - assert(is_valid_setting, "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)") - ctx.k0 = util.U64_LE(key[:8]) - ctx.k1 = util.U64_LE(key[8:]) - ctx.v0 = 0x736f6d6570736575 ~ ctx.k0 - ctx.v1 = 0x646f72616e646f6d ~ ctx.k1 - ctx.v2 = 0x6c7967656e657261 ~ ctx.k0 - ctx.v3 = 0x7465646279746573 ~ ctx.k1 - ctx.is_initialized = true + assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16") + ctx.c_rounds = c_rounds + ctx.d_rounds = d_rounds + is_valid_setting := + (ctx.c_rounds == 1 && ctx.d_rounds == 3) || + (ctx.c_rounds == 2 && ctx.d_rounds == 4) || + (ctx.c_rounds == 4 && ctx.d_rounds == 8) + assert( + is_valid_setting, + "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)", + ) + ctx.k0 = util.U64_LE(key[:8]) + ctx.k1 = util.U64_LE(key[8:]) + ctx.v0 = 0x736f6d6570736575 ~ ctx.k0 + ctx.v1 = 0x646f72616e646f6d ~ ctx.k1 + ctx.v2 = 0x6c7967656e657261 ~ ctx.k0 + ctx.v3 = 0x7465646279746573 ~ ctx.k1 + ctx.is_initialized = true } update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized, "crypto/siphash: Context is not initialized") - ctx.last_block = len(data) / 8 * 8 - ctx.buf = data - i := 0 - m: u64 - for i < ctx.last_block { - m = u64(ctx.buf[i] & 0xff) - i += 1 + assert(ctx.is_initialized, "crypto/siphash: Context is not initialized") + ctx.last_block = len(data) / 8 * 8 + ctx.buf = data + i := 0 + m: u64 + for i < ctx.last_block { + m = u64(ctx.buf[i] & 0xff) + i += 1 - for r in u64(1)..<8 { - m |= u64(ctx.buf[i] & 0xff) << (r * 8) - i += 1 - } + for r in u64(1) ..< 8 { + m |= u64(ctx.buf[i] & 0xff) << (r * 8) + i += 1 + } - ctx.v3 ~= m - for _ in 0..= ctx.last_block; i -= 1 { - m <<= 8 - m |= u64(ctx.buf[i] & 0xff) - } - m |= u64(len(ctx.buf) << 56) + m: u64 + for i := len(ctx.buf) - 1; i >= ctx.last_block; i -= 1 { + m <<= 8 + m |= u64(ctx.buf[i] & 0xff) + } + m |= u64(len(ctx.buf) << 56) - ctx.v3 ~= m + ctx.v3 ~= m - for _ in 0.. byte { - return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3)) + return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3)) } _collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) { - dst[0] = _get_byte(7, hash) - dst[1] = _get_byte(6, hash) - dst[2] = _get_byte(5, hash) - dst[3] = _get_byte(4, hash) - dst[4] = _get_byte(3, hash) - dst[5] = _get_byte(2, hash) - dst[6] = _get_byte(1, hash) - dst[7] = _get_byte(0, hash) + dst[0] = _get_byte(7, hash) + dst[1] = _get_byte(6, hash) + dst[2] = _get_byte(5, hash) + dst[3] = _get_byte(4, hash) + dst[4] = _get_byte(3, hash) + dst[5] = _get_byte(2, hash) + dst[6] = _get_byte(1, hash) + dst[7] = _get_byte(0, hash) } _compress :: #force_inline proc "contextless" (ctx: ^Context) { - ctx.v0 += ctx.v1 - ctx.v1 = util.ROTL64(ctx.v1, 13) - ctx.v1 ~= ctx.v0 - ctx.v0 = util.ROTL64(ctx.v0, 32) - ctx.v2 += ctx.v3 - ctx.v3 = util.ROTL64(ctx.v3, 16) - ctx.v3 ~= ctx.v2 - ctx.v0 += ctx.v3 - ctx.v3 = util.ROTL64(ctx.v3, 21) - ctx.v3 ~= ctx.v0 - ctx.v2 += ctx.v1 - ctx.v1 = util.ROTL64(ctx.v1, 17) - ctx.v1 ~= ctx.v2 - ctx.v2 = util.ROTL64(ctx.v2, 32) + ctx.v0 += ctx.v1 + ctx.v1 = util.ROTL64(ctx.v1, 13) + ctx.v1 ~= ctx.v0 + ctx.v0 = util.ROTL64(ctx.v0, 32) + ctx.v2 += ctx.v3 + ctx.v3 = util.ROTL64(ctx.v3, 16) + ctx.v3 ~= ctx.v2 + ctx.v0 += ctx.v3 + ctx.v3 = util.ROTL64(ctx.v3, 21) + ctx.v3 ~= ctx.v0 + ctx.v2 += ctx.v1 + ctx.v1 = util.ROTL64(ctx.v1, 17) + ctx.v1 ~= ctx.v2 + ctx.v2 = util.ROTL64(ctx.v2, 32) } From 811132ccbd8032f1d668eaeb23a9b533b7851bc0 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 10:29:35 +0900 Subject: [PATCH 071/160] core/crypto/sm3: odinfmt (NFC) --- core/crypto/sm3/sm3.odin | 310 ++++++++++++++++++++------------------- 1 file changed, 159 insertions(+), 151 deletions(-) diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index 9e684ff08..017cf2246 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -10,8 +10,8 @@ package sm3 Implementation of the SM3 hashing algorithm, as defined in */ -import "core:os" import "core:io" +import "core:os" import "../util" @@ -24,77 +24,77 @@ DIGEST_SIZE :: 32 // hash_string will hash the given input and return the // computed hash hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) + return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: Sm3_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash + hash: [DIGEST_SIZE]byte + ctx: Sm3_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_string_to_buffer will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) + hash_bytes_to_buffer(transmute([]byte)(data), hash) } // hash_bytes_to_buffer will hash the given input and write the // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: Sm3_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Sm3_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: Sm3_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true + hash: [DIGEST_SIZE]byte + ctx: Sm3_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [DIGEST_SIZE]byte{}, false } hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, + hash_stream, + hash_file, + hash_bytes, + hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -102,63 +102,63 @@ hash :: proc { */ init :: proc(ctx: ^Sm3_Context) { - ctx.state[0] = IV[0] - ctx.state[1] = IV[1] - ctx.state[2] = IV[2] - ctx.state[3] = IV[3] - ctx.state[4] = IV[4] - ctx.state[5] = IV[5] - ctx.state[6] = IV[6] - ctx.state[7] = IV[7] + ctx.state[0] = IV[0] + ctx.state[1] = IV[1] + ctx.state[2] = IV[2] + ctx.state[3] = IV[3] + ctx.state[4] = IV[4] + ctx.state[5] = IV[5] + ctx.state[6] = IV[6] + ctx.state[7] = IV[7] } update :: proc(ctx: ^Sm3_Context, data: []byte) { - data := data - ctx.length += u64(len(data)) + data := data + ctx.length += u64(len(data)) - if ctx.bitlength > 0 { - n := copy(ctx.x[ctx.bitlength:], data[:]) - ctx.bitlength += u64(n) - if ctx.bitlength == 64 { - block(ctx, ctx.x[:]) - ctx.bitlength = 0 - } - data = data[n:] - } - if len(data) >= 64 { - n := len(data) &~ (64 - 1) - block(ctx, data[:n]) - data = data[n:] - } - if len(data) > 0 { - ctx.bitlength = u64(copy(ctx.x[:], data[:])) - } + if ctx.bitlength > 0 { + n := copy(ctx.x[ctx.bitlength:], data[:]) + ctx.bitlength += u64(n) + if ctx.bitlength == 64 { + block(ctx, ctx.x[:]) + ctx.bitlength = 0 + } + data = data[n:] + } + if len(data) >= 64 { + n := len(data) &~ (64 - 1) + block(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.bitlength = u64(copy(ctx.x[:], data[:])) + } } final :: proc(ctx: ^Sm3_Context, hash: []byte) { - length := ctx.length + length := ctx.length - pad: [64]byte - pad[0] = 0x80 - if length % 64 < 56 { - update(ctx, pad[0: 56 - length % 64]) - } else { - update(ctx, pad[0: 64 + 56 - length % 64]) - } + pad: [64]byte + pad[0] = 0x80 + if length % 64 < 56 { + update(ctx, pad[0:56 - length % 64]) + } else { + update(ctx, pad[0:64 + 56 - length % 64]) + } - length <<= 3 - util.PUT_U64_BE(pad[:], length) - update(ctx, pad[0: 8]) - assert(ctx.bitlength == 0) + length <<= 3 + util.PUT_U64_BE(pad[:], length) + update(ctx, pad[0:8]) + assert(ctx.bitlength == 0) - util.PUT_U32_BE(hash[0:], ctx.state[0]) - util.PUT_U32_BE(hash[4:], ctx.state[1]) - util.PUT_U32_BE(hash[8:], ctx.state[2]) - util.PUT_U32_BE(hash[12:], ctx.state[3]) - util.PUT_U32_BE(hash[16:], ctx.state[4]) - util.PUT_U32_BE(hash[20:], ctx.state[5]) - util.PUT_U32_BE(hash[24:], ctx.state[6]) - util.PUT_U32_BE(hash[28:], ctx.state[7]) + util.PUT_U32_BE(hash[0:], ctx.state[0]) + util.PUT_U32_BE(hash[4:], ctx.state[1]) + util.PUT_U32_BE(hash[8:], ctx.state[2]) + util.PUT_U32_BE(hash[12:], ctx.state[3]) + util.PUT_U32_BE(hash[16:], ctx.state[4]) + util.PUT_U32_BE(hash[20:], ctx.state[5]) + util.PUT_U32_BE(hash[24:], ctx.state[6]) + util.PUT_U32_BE(hash[28:], ctx.state[7]) } /* @@ -166,85 +166,93 @@ final :: proc(ctx: ^Sm3_Context, hash: []byte) { */ Sm3_Context :: struct { - state: [8]u32, - x: [64]byte, - bitlength: u64, - length: u64, + state: [8]u32, + x: [64]byte, + bitlength: u64, + length: u64, } IV := [8]u32 { - 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, - 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e, + 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, + 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e, } block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { - buf := buf + buf := buf - w: [68]u32 - wp: [64]u32 + w: [68]u32 + wp: [64]u32 - state0, state1, state2, state3 := ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] - state4, state5, state6, state7 := ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] + state0, state1, state2, state3 := ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] + state4, state5, state6, state7 := ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] - for len(buf) >= 64 { - for i := 0; i < 16; i += 1 { - j := i * 4 - w[i] = u32(buf[j]) << 24 | u32(buf[j + 1]) << 16 | u32(buf[j + 2]) << 8 | u32(buf[j + 3]) - } - for i := 16; i < 68; i += 1 { - p1v := w[i - 16] ~ w[i - 9] ~ util.ROTL32(w[i - 3], 15) - // @note(zh): inlined P1 - w[i] = p1v ~ util.ROTL32(p1v, 15) ~ util.ROTL32(p1v, 23) ~ util.ROTL32(w[i - 13], 7) ~ w[i - 6] - } - for i := 0; i < 64; i += 1 { - wp[i] = w[i] ~ w[i + 4] - } + for len(buf) >= 64 { + for i := 0; i < 16; i += 1 { + j := i * 4 + w[i] = + u32(buf[j]) << 24 | u32(buf[j + 1]) << 16 | u32(buf[j + 2]) << 8 | u32(buf[j + 3]) + } + for i := 16; i < 68; i += 1 { + p1v := w[i - 16] ~ w[i - 9] ~ util.ROTL32(w[i - 3], 15) + // @note(zh): inlined P1 + w[i] = + p1v ~ + util.ROTL32(p1v, 15) ~ + util.ROTL32(p1v, 23) ~ + util.ROTL32(w[i - 13], 7) ~ + w[i - 6] + } + for i := 0; i < 64; i += 1 { + wp[i] = w[i] ~ w[i + 4] + } - a, b, c, d := state0, state1, state2, state3 - e, f, g, h := state4, state5, state6, state7 + a, b, c, d := state0, state1, state2, state3 + e, f, g, h := state4, state5, state6, state7 - for i := 0; i < 16; i += 1 { - v1 := util.ROTL32(u32(a), 12) - ss1 := util.ROTL32(v1 + u32(e) + util.ROTL32(0x79cc4519, i), 7) - ss2 := ss1 ~ v1 + for i := 0; i < 16; i += 1 { + v1 := util.ROTL32(u32(a), 12) + ss1 := util.ROTL32(v1 + u32(e) + util.ROTL32(0x79cc4519, i), 7) + ss2 := ss1 ~ v1 - // @note(zh): inlined FF1 - tt1 := u32(a ~ b ~ c) + u32(d) + ss2 + wp[i] - // @note(zh): inlined GG1 - tt2 := u32(e ~ f ~ g) + u32(h) + ss1 + w[i] + // @note(zh): inlined FF1 + tt1 := u32(a ~ b ~ c) + u32(d) + ss2 + wp[i] + // @note(zh): inlined GG1 + tt2 := u32(e ~ f ~ g) + u32(h) + ss1 + w[i] - a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c - // @note(zh): inlined P0 - e, f, g, h = (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g - } + a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c + // @note(zh): inlined P0 + e, f, g, h = + (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g + } - for i := 16; i < 64; i += 1 { - v := util.ROTL32(u32(a), 12) - ss1 := util.ROTL32(v + u32(e) + util.ROTL32(0x7a879d8a, i % 32), 7) - ss2 := ss1 ~ v + for i := 16; i < 64; i += 1 { + v := util.ROTL32(u32(a), 12) + ss1 := util.ROTL32(v + u32(e) + util.ROTL32(0x7a879d8a, i % 32), 7) + ss2 := ss1 ~ v - // @note(zh): inlined FF2 - tt1 := u32(((a & b) | (a & c) | (b & c)) + d) + ss2 + wp[i] - // @note(zh): inlined GG2 - tt2 := u32(((e & f) | ((~e) & g)) + h) + ss1 + w[i] + // @note(zh): inlined FF2 + tt1 := u32(((a & b) | (a & c) | (b & c)) + d) + ss2 + wp[i] + // @note(zh): inlined GG2 + tt2 := u32(((e & f) | ((~e) & g)) + h) + ss1 + w[i] - a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c - // @note(zh): inlined P0 - e, f, g, h = (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g - } + a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c + // @note(zh): inlined P0 + e, f, g, h = + (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g + } - state0 ~= a - state1 ~= b - state2 ~= c - state3 ~= d - state4 ~= e - state5 ~= f - state6 ~= g - state7 ~= h + state0 ~= a + state1 ~= b + state2 ~= c + state3 ~= d + state4 ~= e + state5 ~= f + state6 ~= g + state7 ~= h - buf = buf[64:] - } + buf = buf[64:] + } - ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] = state0, state1, state2, state3 - ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] = state4, state5, state6, state7 + ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] = state0, state1, state2, state3 + ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] = state4, state5, state6, state7 } From 3902273d68d31effce50b743b329cd4c6e5142ce Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 10:25:22 +0900 Subject: [PATCH 072/160] core/crypto/_blake2: Cleanups - Use `encoding/endian` - Add `@(private)` annotations to internals - Add some descriptive comments in the unrolled compression functions --- core/crypto/_blake2/blake2.odin | 109 +++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/core/crypto/_blake2/blake2.odin b/core/crypto/_blake2/blake2.odin index 55ef2d6c9..c1b5c5dad 100644 --- a/core/crypto/_blake2/blake2.odin +++ b/core/crypto/_blake2/blake2.odin @@ -10,7 +10,7 @@ package _blake2 Implementation of the BLAKE2 hashing algorithm, as defined in and */ -import "../util" +import "core:encoding/endian" BLAKE2S_BLOCK_SIZE :: 64 BLAKE2S_SIZE :: 32 @@ -65,11 +65,13 @@ Blake2_Tree :: struct { is_last_node: bool, } +@(private) BLAKE2S_IV := [8]u32 { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, } +@(private) BLAKE2B_IV := [8]u64 { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, @@ -108,7 +110,7 @@ init :: proc(ctx: ^$T) { if ctx.cfg.tree != nil { p[2] = ctx.cfg.tree.(Blake2_Tree).fanout p[3] = ctx.cfg.tree.(Blake2_Tree).max_depth - util.PUT_U32_LE(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size) + endian.unchecked_put_u32le(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size) when T == Blake2s_Context { p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset) p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8) @@ -119,7 +121,7 @@ init :: proc(ctx: ^$T) { p[14] = ctx.cfg.tree.(Blake2_Tree).node_depth p[15] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size } else when T == Blake2b_Context { - util.PUT_U64_LE(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset) + endian.unchecked_put_u64le(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset) p[16] = ctx.cfg.tree.(Blake2_Tree).node_depth p[17] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size } @@ -129,10 +131,10 @@ init :: proc(ctx: ^$T) { ctx.size = ctx.cfg.size for i := 0; i < 8; i += 1 { when T == Blake2s_Context { - ctx.h[i] = BLAKE2S_IV[i] ~ util.U32_LE(p[i * 4:]) + ctx.h[i] = BLAKE2S_IV[i] ~ endian.unchecked_get_u32le(p[i * 4:]) } when T == Blake2b_Context { - ctx.h[i] = BLAKE2B_IV[i] ~ util.U64_LE(p[i * 8:]) + ctx.h[i] = BLAKE2B_IV[i] ~ endian.unchecked_get_u64le(p[i * 8:]) } } if ctx.cfg.tree != nil && ctx.cfg.tree.(Blake2_Tree).is_last_node { @@ -148,6 +150,8 @@ init :: proc(ctx: ^$T) { if ctx.is_keyed { update(ctx, ctx.padded_key[:]) } + + ctx.nx = 0 } update :: proc "contextless" (ctx: ^$T, p: []byte) { @@ -185,6 +189,7 @@ final :: proc "contextless" (ctx: ^$T, hash: []byte) { } } +@(private) blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) { if ctx.is_keyed { for i := 0; i < len(ctx.padded_key); i += 1 { @@ -205,16 +210,12 @@ blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) { blocks(ctx, ctx.x[:]) - j := 0 - for s, _ in ctx.h[:(ctx.size - 1) / 4 + 1] { - hash[j + 0] = byte(s >> 0) - hash[j + 1] = byte(s >> 8) - hash[j + 2] = byte(s >> 16) - hash[j + 3] = byte(s >> 24) - j += 4 + for i := 0; i < BLAKE2S_SIZE / 4; i += 1 { + endian.unchecked_put_u32le(hash[i * 4:], ctx.h[i]) } } +@(private) blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) { if ctx.is_keyed { for i := 0; i < len(ctx.padded_key); i += 1 { @@ -235,20 +236,12 @@ blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) { blocks(ctx, ctx.x[:]) - j := 0 - for s, _ in ctx.h[:(ctx.size - 1) / 8 + 1] { - hash[j + 0] = byte(s >> 0) - hash[j + 1] = byte(s >> 8) - hash[j + 2] = byte(s >> 16) - hash[j + 3] = byte(s >> 24) - hash[j + 4] = byte(s >> 32) - hash[j + 5] = byte(s >> 40) - hash[j + 6] = byte(s >> 48) - hash[j + 7] = byte(s >> 56) - j += 8 + for i := 0; i < BLAKE2B_SIZE / 8; i += 1 { + endian.unchecked_put_u64le(hash[i * 8:], ctx.h[i]) } } +@(private) blocks :: proc "contextless" (ctx: ^$T, p: []byte) { when T == Blake2s_Context { blake2s_blocks(ctx, p) @@ -258,6 +251,7 @@ blocks :: proc "contextless" (ctx: ^$T, p: []byte) { } } +@(private) blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []byte) { h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] @@ -276,12 +270,13 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v13 := BLAKE2S_IV[5] ~ ctx.t[1] v14 := BLAKE2S_IV[6] ~ ctx.f[0] v15 := BLAKE2S_IV[7] ~ ctx.f[1] - m: [16]u32 - j := 0 + + m: [16]u32 = --- for i := 0; i < 16; i += 1 { - m[i] = u32(p[j]) | u32(p[j + 1]) << 8 | u32(p[j + 2]) << 16 | u32(p[j + 3]) << 24 - j += 4 + m[i] = endian.unchecked_get_u32le(p[i * 4:]) } + + // Round 1 v0 += m[0] v0 += v4 v12 ~= v0 @@ -394,6 +389,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 2 v0 += m[14] v0 += v4 v12 ~= v0 @@ -506,6 +503,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 3 v0 += m[11] v0 += v4 v12 ~= v0 @@ -618,6 +617,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 4 v0 += m[7] v0 += v4 v12 ~= v0 @@ -730,6 +731,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 5 v0 += m[9] v0 += v4 v12 ~= v0 @@ -842,6 +845,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 6 v0 += m[2] v0 += v4 v12 ~= v0 @@ -954,6 +959,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 7 v0 += m[12] v0 += v4 v12 ~= v0 @@ -1066,6 +1073,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 8 v0 += m[13] v0 += v4 v12 ~= v0 @@ -1178,6 +1187,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 9 v0 += m[6] v0 += v4 v12 ~= v0 @@ -1290,6 +1301,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + + // Round 10 v0 += m[10] v0 += v4 v12 ~= v0 @@ -1402,6 +1415,7 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (32 - 7) | v5 >> 7 + h0 ~= v0 ~ v8 h1 ~= v1 ~ v9 h2 ~= v2 ~ v10 @@ -1410,12 +1424,14 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: [] h5 ~= v5 ~ v13 h6 ~= v6 ~ v14 h7 ~= v7 ~ v15 + p = p[BLAKE2S_BLOCK_SIZE:] } ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 } +@(private) blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []byte) { h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] @@ -1434,20 +1450,13 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v13 := BLAKE2B_IV[5] ~ ctx.t[1] v14 := BLAKE2B_IV[6] ~ ctx.f[0] v15 := BLAKE2B_IV[7] ~ ctx.f[1] + m: [16]u64 = --- - j := 0 for i := 0; i < 16; i += 1 { - m[i] = - u64(p[j]) | - u64(p[j + 1]) << 8 | - u64(p[j + 2]) << 16 | - u64(p[j + 3]) << 24 | - u64(p[j + 4]) << 32 | - u64(p[j + 5]) << 40 | - u64(p[j + 6]) << 48 | - u64(p[j + 7]) << 56 - j += 8 + m[i] = endian.unchecked_get_u64le(p[i * 8:]) } + + // Round 1 v0 += m[0] v0 += v4 v12 ~= v0 @@ -1560,6 +1569,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 2 v0 += m[14] v0 += v4 v12 ~= v0 @@ -1672,6 +1683,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 3 v0 += m[11] v0 += v4 v12 ~= v0 @@ -1784,6 +1797,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 4 v0 += m[7] v0 += v4 v12 ~= v0 @@ -1896,6 +1911,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 5 v0 += m[9] v0 += v4 v12 ~= v0 @@ -2008,6 +2025,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 6 v0 += m[2] v0 += v4 v12 ~= v0 @@ -2120,6 +2139,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 7 v0 += m[12] v0 += v4 v12 ~= v0 @@ -2232,6 +2253,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 8 v0 += m[13] v0 += v4 v12 ~= v0 @@ -2344,6 +2367,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 9 v0 += m[6] v0 += v4 v12 ~= v0 @@ -2456,6 +2481,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 10 v0 += m[10] v0 += v4 v12 ~= v0 @@ -2568,6 +2595,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 11 v0 += m[0] v0 += v4 v12 ~= v0 @@ -2680,6 +2709,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + + // Round 12 v0 += m[14] v0 += v4 v12 ~= v0 @@ -2792,6 +2823,7 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] v10 += v15 v5 ~= v10 v5 = v5 << (64 - 63) | v5 >> 63 + h0 ~= v0 ~ v8 h1 ~= v1 ~ v9 h2 ~= v2 ~ v10 @@ -2800,6 +2832,7 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: [] h5 ~= v5 ~ v13 h6 ~= v6 ~ v14 h7 ~= v7 ~ v15 + p = p[BLAKE2B_BLOCK_SIZE:] } ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = From fa1cb28c8fbf0b24dbfc5adf681e0e34a20281c8 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Tue, 14 Nov 2023 15:48:27 +0900 Subject: [PATCH 073/160] core/crypto/chacha20: Cleanups - Use `encoding/endian` - Use `math/bits` --- core/crypto/chacha20/chacha20.odin | 315 +++++++++++++---------------- 1 file changed, 135 insertions(+), 180 deletions(-) diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin index b29dc1228..43b3303c2 100644 --- a/core/crypto/chacha20/chacha20.odin +++ b/core/crypto/chacha20/chacha20.odin @@ -1,6 +1,6 @@ package chacha20 -import "core:crypto/util" +import "core:encoding/endian" import "core:math/bits" import "core:mem" @@ -60,23 +60,23 @@ init :: proc (ctx: ^Context, key, nonce: []byte) { ctx._s[1] = _SIGMA_1 ctx._s[2] = _SIGMA_2 ctx._s[3] = _SIGMA_3 - ctx._s[4] = util.U32_LE(k[0:4]) - ctx._s[5] = util.U32_LE(k[4:8]) - ctx._s[6] = util.U32_LE(k[8:12]) - ctx._s[7] = util.U32_LE(k[12:16]) - ctx._s[8] = util.U32_LE(k[16:20]) - ctx._s[9] = util.U32_LE(k[20:24]) - ctx._s[10] = util.U32_LE(k[24:28]) - ctx._s[11] = util.U32_LE(k[28:32]) + ctx._s[4] = endian.unchecked_get_u32le(k[0:4]) + ctx._s[5] = endian.unchecked_get_u32le(k[4:8]) + ctx._s[6] = endian.unchecked_get_u32le(k[8:12]) + ctx._s[7] = endian.unchecked_get_u32le(k[12:16]) + ctx._s[8] = endian.unchecked_get_u32le(k[16:20]) + ctx._s[9] = endian.unchecked_get_u32le(k[20:24]) + ctx._s[10] = endian.unchecked_get_u32le(k[24:28]) + ctx._s[11] = endian.unchecked_get_u32le(k[28:32]) ctx._s[12] = 0 if !is_xchacha { - ctx._s[13] = util.U32_LE(n[0:4]) - ctx._s[14] = util.U32_LE(n[4:8]) - ctx._s[15] = util.U32_LE(n[8:12]) + ctx._s[13] = endian.unchecked_get_u32le(n[0:4]) + ctx._s[14] = endian.unchecked_get_u32le(n[4:8]) + ctx._s[15] = endian.unchecked_get_u32le(n[8:12]) } else { ctx._s[13] = 0 - ctx._s[14] = util.U32_LE(n[0:4]) - ctx._s[15] = util.U32_LE(n[4:8]) + ctx._s[14] = endian.unchecked_get_u32le(n[0:4]) + ctx._s[15] = endian.unchecked_get_u32le(n[4:8]) // The sub-key is stored in the keystream buffer. While // this will be overwritten in most circumstances, explicitly @@ -221,114 +221,114 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) { // quarterround(x, 0, 4, 8, 12) x0 += x4 x12 ~= x0 - x12 = util.ROTL32(x12, 16) + x12 = bits.rotate_left32(x12, 16) x8 += x12 x4 ~= x8 - x4 = util.ROTL32(x4, 12) + x4 = bits.rotate_left32(x4, 12) x0 += x4 x12 ~= x0 - x12 = util.ROTL32(x12, 8) + x12 = bits.rotate_left32(x12, 8) x8 += x12 x4 ~= x8 - x4 = util.ROTL32(x4, 7) + x4 = bits.rotate_left32(x4, 7) // quarterround(x, 1, 5, 9, 13) x1 += x5 x13 ~= x1 - x13 = util.ROTL32(x13, 16) + x13 = bits.rotate_left32(x13, 16) x9 += x13 x5 ~= x9 - x5 = util.ROTL32(x5, 12) + x5 = bits.rotate_left32(x5, 12) x1 += x5 x13 ~= x1 - x13 = util.ROTL32(x13, 8) + x13 = bits.rotate_left32(x13, 8) x9 += x13 x5 ~= x9 - x5 = util.ROTL32(x5, 7) + x5 = bits.rotate_left32(x5, 7) // quarterround(x, 2, 6, 10, 14) x2 += x6 x14 ~= x2 - x14 = util.ROTL32(x14, 16) + x14 = bits.rotate_left32(x14, 16) x10 += x14 x6 ~= x10 - x6 = util.ROTL32(x6, 12) + x6 = bits.rotate_left32(x6, 12) x2 += x6 x14 ~= x2 - x14 = util.ROTL32(x14, 8) + x14 = bits.rotate_left32(x14, 8) x10 += x14 x6 ~= x10 - x6 = util.ROTL32(x6, 7) + x6 = bits.rotate_left32(x6, 7) // quarterround(x, 3, 7, 11, 15) x3 += x7 x15 ~= x3 - x15 = util.ROTL32(x15, 16) + x15 = bits.rotate_left32(x15, 16) x11 += x15 x7 ~= x11 - x7 = util.ROTL32(x7, 12) + x7 = bits.rotate_left32(x7, 12) x3 += x7 x15 ~= x3 - x15 = util.ROTL32(x15, 8) + x15 = bits.rotate_left32(x15, 8) x11 += x15 x7 ~= x11 - x7 = util.ROTL32(x7, 7) + x7 = bits.rotate_left32(x7, 7) // quarterround(x, 0, 5, 10, 15) x0 += x5 x15 ~= x0 - x15 = util.ROTL32(x15, 16) + x15 = bits.rotate_left32(x15, 16) x10 += x15 x5 ~= x10 - x5 = util.ROTL32(x5, 12) + x5 = bits.rotate_left32(x5, 12) x0 += x5 x15 ~= x0 - x15 = util.ROTL32(x15, 8) + x15 = bits.rotate_left32(x15, 8) x10 += x15 x5 ~= x10 - x5 = util.ROTL32(x5, 7) + x5 = bits.rotate_left32(x5, 7) // quarterround(x, 1, 6, 11, 12) x1 += x6 x12 ~= x1 - x12 = util.ROTL32(x12, 16) + x12 = bits.rotate_left32(x12, 16) x11 += x12 x6 ~= x11 - x6 = util.ROTL32(x6, 12) + x6 = bits.rotate_left32(x6, 12) x1 += x6 x12 ~= x1 - x12 = util.ROTL32(x12, 8) + x12 = bits.rotate_left32(x12, 8) x11 += x12 x6 ~= x11 - x6 = util.ROTL32(x6, 7) + x6 = bits.rotate_left32(x6, 7) // quarterround(x, 2, 7, 8, 13) x2 += x7 x13 ~= x2 - x13 = util.ROTL32(x13, 16) + x13 = bits.rotate_left32(x13, 16) x8 += x13 x7 ~= x8 - x7 = util.ROTL32(x7, 12) + x7 = bits.rotate_left32(x7, 12) x2 += x7 x13 ~= x2 - x13 = util.ROTL32(x13, 8) + x13 = bits.rotate_left32(x13, 8) x8 += x13 x7 ~= x8 - x7 = util.ROTL32(x7, 7) + x7 = bits.rotate_left32(x7, 7) // quarterround(x, 3, 4, 9, 14) x3 += x4 x14 ~= x3 - x14 = util.ROTL32(x14, 16) + x14 = bits.rotate_left32(x14, 16) x9 += x14 x4 ~= x9 - x4 = util.ROTL32(x4, 12) + x4 = bits.rotate_left32(x4, 12) x3 += x4 x14 ~= x3 - x14 = util.ROTL32(x14, 8) + x14 = bits.rotate_left32(x14, 8) x9 += x14 x4 ~= x9 - x4 = util.ROTL32(x4, 7) + x4 = bits.rotate_left32(x4, 7) } x0 += _SIGMA_0 @@ -352,93 +352,48 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) { // this is "use vector operations", support for that is currently // a work in progress/to be designed. // - // Until dedicated assembly can be written leverage the fact that - // the callers of this routine ensure that src/dst are valid. + // In the meantime: + // - The caller(s) ensure that src/dst are valid. + // - The compiler knows if the target is picky about alignment. - when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 { - // util.PUT_U32_LE/util.U32_LE are not required on little-endian - // systems that also happen to not be strict about aligned - // memory access. - - dst_p := transmute(^[16]u32)(&dst[0]) + #no_bounds_check { if src != nil { - src_p := transmute(^[16]u32)(&src[0]) - dst_p[0] = src_p[0] ~ x0 - dst_p[1] = src_p[1] ~ x1 - dst_p[2] = src_p[2] ~ x2 - dst_p[3] = src_p[3] ~ x3 - dst_p[4] = src_p[4] ~ x4 - dst_p[5] = src_p[5] ~ x5 - dst_p[6] = src_p[6] ~ x6 - dst_p[7] = src_p[7] ~ x7 - dst_p[8] = src_p[8] ~ x8 - dst_p[9] = src_p[9] ~ x9 - dst_p[10] = src_p[10] ~ x10 - dst_p[11] = src_p[11] ~ x11 - dst_p[12] = src_p[12] ~ x12 - dst_p[13] = src_p[13] ~ x13 - dst_p[14] = src_p[14] ~ x14 - dst_p[15] = src_p[15] ~ x15 + endian.unchecked_put_u32le(dst[0:4], endian.unchecked_get_u32le(src[0:4]) ~ x0) + endian.unchecked_put_u32le(dst[4:8], endian.unchecked_get_u32le(src[4:8]) ~ x1) + endian.unchecked_put_u32le(dst[8:12], endian.unchecked_get_u32le(src[8:12]) ~ x2) + endian.unchecked_put_u32le(dst[12:16], endian.unchecked_get_u32le(src[12:16]) ~ x3) + endian.unchecked_put_u32le(dst[16:20], endian.unchecked_get_u32le(src[16:20]) ~ x4) + endian.unchecked_put_u32le(dst[20:24], endian.unchecked_get_u32le(src[20:24]) ~ x5) + endian.unchecked_put_u32le(dst[24:28], endian.unchecked_get_u32le(src[24:28]) ~ x6) + endian.unchecked_put_u32le(dst[28:32], endian.unchecked_get_u32le(src[28:32]) ~ x7) + endian.unchecked_put_u32le(dst[32:36], endian.unchecked_get_u32le(src[32:36]) ~ x8) + endian.unchecked_put_u32le(dst[36:40], endian.unchecked_get_u32le(src[36:40]) ~ x9) + endian.unchecked_put_u32le(dst[40:44], endian.unchecked_get_u32le(src[40:44]) ~ x10) + endian.unchecked_put_u32le(dst[44:48], endian.unchecked_get_u32le(src[44:48]) ~ x11) + endian.unchecked_put_u32le(dst[48:52], endian.unchecked_get_u32le(src[48:52]) ~ x12) + endian.unchecked_put_u32le(dst[52:56], endian.unchecked_get_u32le(src[52:56]) ~ x13) + endian.unchecked_put_u32le(dst[56:60], endian.unchecked_get_u32le(src[56:60]) ~ x14) + endian.unchecked_put_u32le(dst[60:64], endian.unchecked_get_u32le(src[60:64]) ~ x15) src = src[_BLOCK_SIZE:] } else { - dst_p[0] = x0 - dst_p[1] = x1 - dst_p[2] = x2 - dst_p[3] = x3 - dst_p[4] = x4 - dst_p[5] = x5 - dst_p[6] = x6 - dst_p[7] = x7 - dst_p[8] = x8 - dst_p[9] = x9 - dst_p[10] = x10 - dst_p[11] = x11 - dst_p[12] = x12 - dst_p[13] = x13 - dst_p[14] = x14 - dst_p[15] = x15 + endian.unchecked_put_u32le(dst[0:4], x0) + endian.unchecked_put_u32le(dst[4:8], x1) + endian.unchecked_put_u32le(dst[8:12], x2) + endian.unchecked_put_u32le(dst[12:16], x3) + endian.unchecked_put_u32le(dst[16:20], x4) + endian.unchecked_put_u32le(dst[20:24], x5) + endian.unchecked_put_u32le(dst[24:28], x6) + endian.unchecked_put_u32le(dst[28:32], x7) + endian.unchecked_put_u32le(dst[32:36], x8) + endian.unchecked_put_u32le(dst[36:40], x9) + endian.unchecked_put_u32le(dst[40:44], x10) + endian.unchecked_put_u32le(dst[44:48], x11) + endian.unchecked_put_u32le(dst[48:52], x12) + endian.unchecked_put_u32le(dst[52:56], x13) + endian.unchecked_put_u32le(dst[56:60], x14) + endian.unchecked_put_u32le(dst[60:64], x15) } dst = dst[_BLOCK_SIZE:] - } else { - #no_bounds_check { - if src != nil { - util.PUT_U32_LE(dst[0:4], util.U32_LE(src[0:4]) ~ x0) - util.PUT_U32_LE(dst[4:8], util.U32_LE(src[4:8]) ~ x1) - util.PUT_U32_LE(dst[8:12], util.U32_LE(src[8:12]) ~ x2) - util.PUT_U32_LE(dst[12:16], util.U32_LE(src[12:16]) ~ x3) - util.PUT_U32_LE(dst[16:20], util.U32_LE(src[16:20]) ~ x4) - util.PUT_U32_LE(dst[20:24], util.U32_LE(src[20:24]) ~ x5) - util.PUT_U32_LE(dst[24:28], util.U32_LE(src[24:28]) ~ x6) - util.PUT_U32_LE(dst[28:32], util.U32_LE(src[28:32]) ~ x7) - util.PUT_U32_LE(dst[32:36], util.U32_LE(src[32:36]) ~ x8) - util.PUT_U32_LE(dst[36:40], util.U32_LE(src[36:40]) ~ x9) - util.PUT_U32_LE(dst[40:44], util.U32_LE(src[40:44]) ~ x10) - util.PUT_U32_LE(dst[44:48], util.U32_LE(src[44:48]) ~ x11) - util.PUT_U32_LE(dst[48:52], util.U32_LE(src[48:52]) ~ x12) - util.PUT_U32_LE(dst[52:56], util.U32_LE(src[52:56]) ~ x13) - util.PUT_U32_LE(dst[56:60], util.U32_LE(src[56:60]) ~ x14) - util.PUT_U32_LE(dst[60:64], util.U32_LE(src[60:64]) ~ x15) - src = src[_BLOCK_SIZE:] - } else { - util.PUT_U32_LE(dst[0:4], x0) - util.PUT_U32_LE(dst[4:8], x1) - util.PUT_U32_LE(dst[8:12], x2) - util.PUT_U32_LE(dst[12:16], x3) - util.PUT_U32_LE(dst[16:20], x4) - util.PUT_U32_LE(dst[20:24], x5) - util.PUT_U32_LE(dst[24:28], x6) - util.PUT_U32_LE(dst[28:32], x7) - util.PUT_U32_LE(dst[32:36], x8) - util.PUT_U32_LE(dst[36:40], x9) - util.PUT_U32_LE(dst[40:44], x10) - util.PUT_U32_LE(dst[44:48], x11) - util.PUT_U32_LE(dst[48:52], x12) - util.PUT_U32_LE(dst[52:56], x13) - util.PUT_U32_LE(dst[56:60], x14) - util.PUT_U32_LE(dst[60:64], x15) - } - dst = dst[_BLOCK_SIZE:] - } } // Increment the counter. Overflow checking is done upon @@ -451,141 +406,141 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) { } @(private) -_hchacha20 :: proc (dst, key, nonce: []byte) { +_hchacha20 :: proc "contextless" (dst, key, nonce: []byte) { x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3 - x4 := util.U32_LE(key[0:4]) - x5 := util.U32_LE(key[4:8]) - x6 := util.U32_LE(key[8:12]) - x7 := util.U32_LE(key[12:16]) - x8 := util.U32_LE(key[16:20]) - x9 := util.U32_LE(key[20:24]) - x10 := util.U32_LE(key[24:28]) - x11 := util.U32_LE(key[28:32]) - x12 := util.U32_LE(nonce[0:4]) - x13 := util.U32_LE(nonce[4:8]) - x14 := util.U32_LE(nonce[8:12]) - x15 := util.U32_LE(nonce[12:16]) + x4 := endian.unchecked_get_u32le(key[0:4]) + x5 := endian.unchecked_get_u32le(key[4:8]) + x6 := endian.unchecked_get_u32le(key[8:12]) + x7 := endian.unchecked_get_u32le(key[12:16]) + x8 := endian.unchecked_get_u32le(key[16:20]) + x9 := endian.unchecked_get_u32le(key[20:24]) + x10 := endian.unchecked_get_u32le(key[24:28]) + x11 := endian.unchecked_get_u32le(key[28:32]) + x12 := endian.unchecked_get_u32le(nonce[0:4]) + x13 := endian.unchecked_get_u32le(nonce[4:8]) + x14 := endian.unchecked_get_u32le(nonce[8:12]) + x15 := endian.unchecked_get_u32le(nonce[12:16]) for i := _ROUNDS; i > 0; i = i - 2 { // quarterround(x, 0, 4, 8, 12) x0 += x4 x12 ~= x0 - x12 = util.ROTL32(x12, 16) + x12 = bits.rotate_left32(x12, 16) x8 += x12 x4 ~= x8 - x4 = util.ROTL32(x4, 12) + x4 = bits.rotate_left32(x4, 12) x0 += x4 x12 ~= x0 - x12 = util.ROTL32(x12, 8) + x12 = bits.rotate_left32(x12, 8) x8 += x12 x4 ~= x8 - x4 = util.ROTL32(x4, 7) + x4 = bits.rotate_left32(x4, 7) // quarterround(x, 1, 5, 9, 13) x1 += x5 x13 ~= x1 - x13 = util.ROTL32(x13, 16) + x13 = bits.rotate_left32(x13, 16) x9 += x13 x5 ~= x9 - x5 = util.ROTL32(x5, 12) + x5 = bits.rotate_left32(x5, 12) x1 += x5 x13 ~= x1 - x13 = util.ROTL32(x13, 8) + x13 = bits.rotate_left32(x13, 8) x9 += x13 x5 ~= x9 - x5 = util.ROTL32(x5, 7) + x5 = bits.rotate_left32(x5, 7) // quarterround(x, 2, 6, 10, 14) x2 += x6 x14 ~= x2 - x14 = util.ROTL32(x14, 16) + x14 = bits.rotate_left32(x14, 16) x10 += x14 x6 ~= x10 - x6 = util.ROTL32(x6, 12) + x6 = bits.rotate_left32(x6, 12) x2 += x6 x14 ~= x2 - x14 = util.ROTL32(x14, 8) + x14 = bits.rotate_left32(x14, 8) x10 += x14 x6 ~= x10 - x6 = util.ROTL32(x6, 7) + x6 = bits.rotate_left32(x6, 7) // quarterround(x, 3, 7, 11, 15) x3 += x7 x15 ~= x3 - x15 = util.ROTL32(x15, 16) + x15 = bits.rotate_left32(x15, 16) x11 += x15 x7 ~= x11 - x7 = util.ROTL32(x7, 12) + x7 = bits.rotate_left32(x7, 12) x3 += x7 x15 ~= x3 - x15 = util.ROTL32(x15, 8) + x15 = bits.rotate_left32(x15, 8) x11 += x15 x7 ~= x11 - x7 = util.ROTL32(x7, 7) + x7 = bits.rotate_left32(x7, 7) // quarterround(x, 0, 5, 10, 15) x0 += x5 x15 ~= x0 - x15 = util.ROTL32(x15, 16) + x15 = bits.rotate_left32(x15, 16) x10 += x15 x5 ~= x10 - x5 = util.ROTL32(x5, 12) + x5 = bits.rotate_left32(x5, 12) x0 += x5 x15 ~= x0 - x15 = util.ROTL32(x15, 8) + x15 = bits.rotate_left32(x15, 8) x10 += x15 x5 ~= x10 - x5 = util.ROTL32(x5, 7) + x5 = bits.rotate_left32(x5, 7) // quarterround(x, 1, 6, 11, 12) x1 += x6 x12 ~= x1 - x12 = util.ROTL32(x12, 16) + x12 = bits.rotate_left32(x12, 16) x11 += x12 x6 ~= x11 - x6 = util.ROTL32(x6, 12) + x6 = bits.rotate_left32(x6, 12) x1 += x6 x12 ~= x1 - x12 = util.ROTL32(x12, 8) + x12 = bits.rotate_left32(x12, 8) x11 += x12 x6 ~= x11 - x6 = util.ROTL32(x6, 7) + x6 = bits.rotate_left32(x6, 7) // quarterround(x, 2, 7, 8, 13) x2 += x7 x13 ~= x2 - x13 = util.ROTL32(x13, 16) + x13 = bits.rotate_left32(x13, 16) x8 += x13 x7 ~= x8 - x7 = util.ROTL32(x7, 12) + x7 = bits.rotate_left32(x7, 12) x2 += x7 x13 ~= x2 - x13 = util.ROTL32(x13, 8) + x13 = bits.rotate_left32(x13, 8) x8 += x13 x7 ~= x8 - x7 = util.ROTL32(x7, 7) + x7 = bits.rotate_left32(x7, 7) // quarterround(x, 3, 4, 9, 14) x3 += x4 x14 ~= x3 - x14 = util.ROTL32(x14, 16) + x14 = bits.rotate_left32(x14, 16) x9 += x14 x4 ~= x9 - x4 = util.ROTL32(x4, 12) + x4 = bits.rotate_left32(x4, 12) x3 += x4 x14 ~= x3 - x14 = util.ROTL32(x14, 8) + x14 = bits.rotate_left32(x14, 8) x9 += x14 x4 ~= x9 - x4 = util.ROTL32(x4, 7) + x4 = bits.rotate_left32(x4, 7) } - util.PUT_U32_LE(dst[0:4], x0) - util.PUT_U32_LE(dst[4:8], x1) - util.PUT_U32_LE(dst[8:12], x2) - util.PUT_U32_LE(dst[12:16], x3) - util.PUT_U32_LE(dst[16:20], x12) - util.PUT_U32_LE(dst[20:24], x13) - util.PUT_U32_LE(dst[24:28], x14) - util.PUT_U32_LE(dst[28:32], x15) + endian.unchecked_put_u32le(dst[0:4], x0) + endian.unchecked_put_u32le(dst[4:8], x1) + endian.unchecked_put_u32le(dst[8:12], x2) + endian.unchecked_put_u32le(dst[12:16], x3) + endian.unchecked_put_u32le(dst[16:20], x12) + endian.unchecked_put_u32le(dst[20:24], x13) + endian.unchecked_put_u32le(dst[24:28], x14) + endian.unchecked_put_u32le(dst[28:32], x15) } From aa5a95a4d1ca83e5ef75c059ddced992dfddc2b3 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Tue, 14 Nov 2023 15:50:36 +0900 Subject: [PATCH 074/160] core/crypto/chacha20poly1305: Cleanups - Use `encoding/endian` --- core/crypto/chacha20poly1305/chacha20poly1305.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/crypto/chacha20poly1305/chacha20poly1305.odin b/core/crypto/chacha20poly1305/chacha20poly1305.odin index ae395f9e0..86fe54e79 100644 --- a/core/crypto/chacha20poly1305/chacha20poly1305.odin +++ b/core/crypto/chacha20poly1305/chacha20poly1305.odin @@ -3,7 +3,7 @@ package chacha20poly1305 import "core:crypto" import "core:crypto/chacha20" import "core:crypto/poly1305" -import "core:crypto/util" +import "core:encoding/endian" import "core:mem" KEY_SIZE :: chacha20.KEY_SIZE @@ -87,8 +87,8 @@ encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) { // mac_data |= num_to_8_le_bytes(aad.length) // mac_data |= num_to_8_le_bytes(ciphertext.length) l_buf := otk[0:16] // Reuse the scratch buffer. - util.PUT_U64_LE(l_buf[0:8], u64(aad_len)) - util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len)) + endian.unchecked_put_u64le(l_buf[0:8], u64(aad_len)) + endian.unchecked_put_u64le(l_buf[8:16], u64(ciphertext_len)) poly1305.update(&mac_ctx, l_buf) // tag = poly1305_mac(mac_data, otk) @@ -128,8 +128,8 @@ decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool { poly1305.update(&mac_ctx, ciphertext) _update_mac_pad16(&mac_ctx, ciphertext_len) l_buf := otk[0:16] // Reuse the scratch buffer. - util.PUT_U64_LE(l_buf[0:8], u64(aad_len)) - util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len)) + endian.unchecked_put_u64le(l_buf[0:8], u64(aad_len)) + endian.unchecked_put_u64le(l_buf[8:16], u64(ciphertext_len)) poly1305.update(&mac_ctx, l_buf) // tag = poly1305_mac(mac_data, otk) From 1279ebe948abe171b9651288187a564a79d51de8 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Tue, 14 Nov 2023 15:47:27 +0900 Subject: [PATCH 075/160] core/crypto/poly1305: Cleanups - Use `encoding/endian` --- core/crypto/_fiat/field_poly1305/field.odin | 53 ++++++++------------- core/crypto/poly1305/poly1305.odin | 8 ++-- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index ca458e079..a103f6fc7 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -1,6 +1,6 @@ package field_poly1305 -import "core:crypto/util" +import "core:encoding/endian" import "core:mem" fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element { @@ -11,7 +11,7 @@ fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) return transmute(^Tight_Field_Element)(arg1) } -fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte, sanitize: bool = true) { +fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte) { // fiat-crypto's deserialization routine effectively processes a // single byte at a time, and wants 256-bits of input for a value // that will be 128-bits or 129-bits. @@ -22,42 +22,29 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a assert(len(arg1) == 16) - when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 { - // While it may be unwise to do deserialization here on our - // own when fiat-crypto provides equivalent functionality, - // doing it this way provides a little under 3x performance - // improvement when optimization is enabled. - src_p := transmute(^[2]u64)(&arg1[0]) - lo := src_p[0] - hi := src_p[1] + // While it may be unwise to do deserialization here on our + // own when fiat-crypto provides equivalent functionality, + // doing it this way provides a little under 3x performance + // improvement when optimization is enabled. + lo := endian.unchecked_get_u64le(arg1[0:]) + hi := endian.unchecked_get_u64le(arg1[8:]) - // This is inspired by poly1305-donna, though adjustments were - // made since a Tight_Field_Element's limbs are 44-bits, 43-bits, - // and 43-bits wide. - // - // Note: This could be transplated into fe_from_u64s, but that - // code is called once per MAC, and is non-criticial path. - hibit := u64(arg2) << 41 // arg2 << 128 - out1[0] = lo & 0xfffffffffff - out1[1] = ((lo >> 44) | (hi << 20)) & 0x7ffffffffff - out1[2] = ((hi >> 23) & 0x7ffffffffff) | hibit - } else { - tmp: [32]byte - copy_slice(tmp[0:16], arg1[:]) - tmp[16] = arg2 - - _fe_from_bytes(out1, &tmp) - if sanitize { - // This is used to deserialize `s` which is confidential. - mem.zero_explicit(&tmp, size_of(tmp)) - } - } + // This is inspired by poly1305-donna, though adjustments were + // made since a Tight_Field_Element's limbs are 44-bits, 43-bits, + // and 43-bits wide. + // + // Note: This could be transplated into fe_from_u64s, but that + // code is called once per MAC, and is non-criticial path. + hibit := u64(arg2) << 41 // arg2 << 128 + out1[0] = lo & 0xfffffffffff + out1[1] = ((lo >> 44) | (hi << 20)) & 0x7ffffffffff + out1[2] = ((hi >> 23) & 0x7ffffffffff) | hibit } fe_from_u64s :: proc "contextless" (out1: ^Tight_Field_Element, lo, hi: u64) { tmp: [32]byte - util.PUT_U64_LE(tmp[0:8], lo) - util.PUT_U64_LE(tmp[8:16], hi) + endian.unchecked_put_u64le(tmp[0:], lo) + endian.unchecked_put_u64le(tmp[8:], hi) _fe_from_bytes(out1, &tmp) diff --git a/core/crypto/poly1305/poly1305.odin b/core/crypto/poly1305/poly1305.odin index ab320c80c..cf60f7166 100644 --- a/core/crypto/poly1305/poly1305.odin +++ b/core/crypto/poly1305/poly1305.odin @@ -1,8 +1,8 @@ package poly1305 import "core:crypto" -import "core:crypto/util" import field "core:crypto/_fiat/field_poly1305" +import "core:encoding/endian" import "core:mem" KEY_SIZE :: 32 @@ -52,8 +52,8 @@ init :: proc (ctx: ^Context, key: []byte) { // r = le_bytes_to_num(key[0..15]) // r = clamp(r) (r &= 0xffffffc0ffffffc0ffffffc0fffffff) - tmp_lo := util.U64_LE(key[0:8]) & 0x0ffffffc0fffffff - tmp_hi := util.U64_LE(key[8:16]) & 0xffffffc0ffffffc + tmp_lo := endian.unchecked_get_u64le(key[0:]) & 0x0ffffffc0fffffff + tmp_hi := endian.unchecked_get_u64le(key[8:]) & 0xffffffc0ffffffc field.fe_from_u64s(&ctx._r, tmp_lo, tmp_hi) // s = le_bytes_to_num(key[16..31]) @@ -151,7 +151,7 @@ _blocks :: proc (ctx: ^Context, msg: []byte, final := false) { data_len := len(data) for data_len >= _BLOCK_SIZE { // n = le_bytes_to_num(msg[((i-1)*16)..*i*16] | [0x01]) - field.fe_from_bytes(&n, data[:_BLOCK_SIZE], final_byte, false) + field.fe_from_bytes(&n, data[:_BLOCK_SIZE], final_byte) // a += n field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &n) // _a unreduced From d16acdc89c406ea07b52e34d54ab7d6f93773b25 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 11:20:59 +0900 Subject: [PATCH 076/160] core/crypto/md5: Cleanups - Use `encoding/endian` - Use `math/bits` - Add `@(private)` annotations to internals --- core/crypto/md5/md5.odin | 52 ++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index 0b04916dc..e451afd20 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -10,12 +10,12 @@ package md5 Implementation of the MD5 hashing algorithm, as defined in RFC 1321 */ +import "core:encoding/endian" import "core:io" +import "core:math/bits" import "core:mem" import "core:os" -import "../util" - /* High level API */ @@ -107,6 +107,9 @@ init :: proc(ctx: ^Md5_Context) { ctx.state[1] = 0xefcdab89 ctx.state[2] = 0x98badcfe ctx.state[3] = 0x10325476 + + ctx.bitlen = 0 + ctx.datalen = 0 } update :: proc(ctx: ^Md5_Context, data: []byte) { @@ -122,8 +125,7 @@ update :: proc(ctx: ^Md5_Context, data: []byte) { } final :: proc(ctx: ^Md5_Context, hash: []byte) { - i: u32 - i = ctx.datalen + i := ctx.datalen if ctx.datalen < 56 { ctx.data[i] = 0x80 @@ -144,26 +146,16 @@ final :: proc(ctx: ^Md5_Context, hash: []byte) { } ctx.bitlen += u64(ctx.datalen * 8) - ctx.data[56] = byte(ctx.bitlen) - ctx.data[57] = byte(ctx.bitlen >> 8) - ctx.data[58] = byte(ctx.bitlen >> 16) - ctx.data[59] = byte(ctx.bitlen >> 24) - ctx.data[60] = byte(ctx.bitlen >> 32) - ctx.data[61] = byte(ctx.bitlen >> 40) - ctx.data[62] = byte(ctx.bitlen >> 48) - ctx.data[63] = byte(ctx.bitlen >> 56) + endian.unchecked_put_u64le(ctx.data[56:], ctx.bitlen) transform(ctx, ctx.data[:]) - for i = 0; i < 4; i += 1 { - hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff - hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff - hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff - hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff + for i = 0; i < DIGEST_SIZE / 4; i += 1 { + endian.unchecked_put_u32le(hash[i * 4:], ctx.state[i]) } } /* - MD4 implementation + MD5 implementation */ BLOCK_SIZE :: 64 @@ -176,34 +168,36 @@ Md5_Context :: struct { } /* - @note(zh): F, G, H and I, as mentioned in the RFC, have been inlined into FF, GG, HH + @note(zh): F, G, H and I, as mentioned in the RFC, have been inlined into FF, GG, HH and II respectively, instead of declaring them separately. */ +@(private) FF :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + ((b & c) | (~b & d)) + m + t, s) + return b + bits.rotate_left32(a + ((b & c) | (~b & d)) + m + t, s) } +@(private) GG :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + ((b & d) | (c & ~d)) + m + t, s) + return b + bits.rotate_left32(a + ((b & d) | (c & ~d)) + m + t, s) } +@(private) HH :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + (b ~ c ~ d) + m + t, s) + return b + bits.rotate_left32(a + (b ~ c ~ d) + m + t, s) } +@(private) II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { - return b + util.ROTL32(a + (c ~ (b | ~d)) + m + t, s) + return b + bits.rotate_left32(a + (c ~ (b | ~d)) + m + t, s) } -transform :: proc(ctx: ^Md5_Context, data: []byte) { - i, j: u32 +@(private) +transform :: proc "contextless" (ctx: ^Md5_Context, data: []byte) { m: [DIGEST_SIZE]u32 - for i, j = 0, 0; i < DIGEST_SIZE; i += 1 { - m[i] = - u32(data[j]) + u32(data[j + 1]) << 8 + u32(data[j + 2]) << 16 + u32(data[j + 3]) << 24 - j += 4 + for i := 0; i < DIGEST_SIZE; i += 1 { + m[i] = endian.unchecked_get_u32le(data[i * 4:]) } a := ctx.state[0] From c7dc1220b36b2f57363febc7005be56bf9c74045 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 11:36:03 +0900 Subject: [PATCH 077/160] core/crypto/sha1: Cleanups - Use `encoding/endian` - Use `math/bits` - Add `@(private)` annotations to internals --- core/crypto/sha1/sha1.odin | 51 ++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index d868fca80..c2cee8098 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -10,12 +10,12 @@ package sha1 Implementation of the SHA1 hashing algorithm, as defined in RFC 3174 */ +import "core:encoding/endian" import "core:io" +import "core:math/bits" import "core:mem" import "core:os" -import "../util" - /* High level API */ @@ -112,6 +112,9 @@ init :: proc(ctx: ^Sha1_Context) { ctx.k[1] = 0x6ed9eba1 ctx.k[2] = 0x8f1bbcdc ctx.k[3] = 0xca62c1d6 + + ctx.datalen = 0 + ctx.bitlen = 0 } update :: proc(ctx: ^Sha1_Context, data: []byte) { @@ -148,22 +151,11 @@ final :: proc(ctx: ^Sha1_Context, hash: []byte) { } ctx.bitlen += u64(ctx.datalen * 8) - ctx.data[63] = u8(ctx.bitlen) - ctx.data[62] = u8(ctx.bitlen >> 8) - ctx.data[61] = u8(ctx.bitlen >> 16) - ctx.data[60] = u8(ctx.bitlen >> 24) - ctx.data[59] = u8(ctx.bitlen >> 32) - ctx.data[58] = u8(ctx.bitlen >> 40) - ctx.data[57] = u8(ctx.bitlen >> 48) - ctx.data[56] = u8(ctx.bitlen >> 56) + endian.unchecked_put_u64be(ctx.data[56:], ctx.bitlen) transform(ctx, ctx.data[:]) - for j: u32 = 0; j < 4; j += 1 { - hash[j] = u8(ctx.state[0] >> (24 - j * 8)) & 0x000000ff - hash[j + 4] = u8(ctx.state[1] >> (24 - j * 8)) & 0x000000ff - hash[j + 8] = u8(ctx.state[2] >> (24 - j * 8)) & 0x000000ff - hash[j + 12] = u8(ctx.state[3] >> (24 - j * 8)) & 0x000000ff - hash[j + 16] = u8(ctx.state[4] >> (24 - j * 8)) & 0x000000ff + for i = 0; i < DIGEST_SIZE / 4; i += 1 { + endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i]) } } @@ -181,14 +173,13 @@ Sha1_Context :: struct { k: [4]u32, } -transform :: proc(ctx: ^Sha1_Context, data: []byte) { - a, b, c, d, e, i, j, t: u32 +@(private) +transform :: proc "contextless" (ctx: ^Sha1_Context, data: []byte) { + a, b, c, d, e, i, t: u32 m: [80]u32 - for i, j = 0, 0; i < 16; i += 1 { - m[i] = - u32(data[j]) << 24 + u32(data[j + 1]) << 16 + u32(data[j + 2]) << 8 + u32(data[j + 3]) - j += 4 + for i = 0; i < 16; i += 1 { + m[i] = endian.unchecked_get_u32be(data[i * 4:]) } for i < 80 { m[i] = (m[i - 3] ~ m[i - 8] ~ m[i - 14] ~ m[i - 16]) @@ -203,36 +194,36 @@ transform :: proc(ctx: ^Sha1_Context, data: []byte) { e = ctx.state[4] for i = 0; i < 20; i += 1 { - t = util.ROTL32(a, 5) + ((b & c) ~ (~b & d)) + e + ctx.k[0] + m[i] + t = bits.rotate_left32(a, 5) + ((b & c) ~ (~b & d)) + e + ctx.k[0] + m[i] e = d d = c - c = util.ROTL32(b, 30) + c = bits.rotate_left32(b, 30) b = a a = t } for i < 40 { - t = util.ROTL32(a, 5) + (b ~ c ~ d) + e + ctx.k[1] + m[i] + t = bits.rotate_left32(a, 5) + (b ~ c ~ d) + e + ctx.k[1] + m[i] e = d d = c - c = util.ROTL32(b, 30) + c = bits.rotate_left32(b, 30) b = a a = t i += 1 } for i < 60 { - t = util.ROTL32(a, 5) + ((b & c) ~ (b & d) ~ (c & d)) + e + ctx.k[2] + m[i] + t = bits.rotate_left32(a, 5) + ((b & c) ~ (b & d) ~ (c & d)) + e + ctx.k[2] + m[i] e = d d = c - c = util.ROTL32(b, 30) + c = bits.rotate_left32(b, 30) b = a a = t i += 1 } for i < 80 { - t = util.ROTL32(a, 5) + (b ~ c ~ d) + e + ctx.k[3] + m[i] + t = bits.rotate_left32(a, 5) + (b ~ c ~ d) + e + ctx.k[3] + m[i] e = d d = c - c = util.ROTL32(b, 30) + c = bits.rotate_left32(b, 30) b = a a = t i += 1 From b0397581db3e99913e2ea17c31deadd7d3a312e9 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Wed, 15 Nov 2023 22:42:03 +0900 Subject: [PATCH 078/160] core/crypto/sha2: Cleanups - Use `encoding/endian` - Use `math/bits` - Add `@(private)` annotations to internals --- core/crypto/sha2/sha2.odin | 68 ++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 4a12eef7e..a63f55476 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -11,12 +11,12 @@ package sha2 and in RFC 3874 */ +import "core:encoding/endian" import "core:io" +import "core:math/bits" import "core:mem" import "core:os" -import "../util" - /* High level API */ @@ -400,6 +400,9 @@ init :: proc(ctx: ^$T) { ctx.h[7] = 0x5be0cd19137e2179 } } + + ctx.tot_len = 0 + ctx.length = 0 } update :: proc(ctx: ^$T, data: []byte) { @@ -453,21 +456,21 @@ final :: proc(ctx: ^$T, hash: []byte) { mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length)) ctx.block[ctx.length] = 0x80 - util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b) + endian.unchecked_put_u32be(ctx.block[pm_len - 4:], len_b) sha2_transf(ctx, ctx.block[:], uint(block_nb)) when T == Sha256_Context { if ctx.is224 { - for i = 0; i < 7; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + for i = 0; i < 7; i += 1 {endian.unchecked_put_u32be(hash[i << 2:], ctx.h[i])} } else { - for i = 0; i < 8; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + for i = 0; i < 8; i += 1 {endian.unchecked_put_u32be(hash[i << 2:], ctx.h[i])} } } else when T == Sha512_Context { if ctx.is384 { - for i = 0; i < 6; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + for i = 0; i < 6; i += 1 {endian.unchecked_put_u64be(hash[i << 3:], ctx.h[i])} } else { - for i = 0; i < 8; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + for i = 0; i < 8; i += 1 {endian.unchecked_put_u64be(hash[i << 3:], ctx.h[i])} } } } @@ -495,6 +498,7 @@ Sha512_Context :: struct { is384: bool, } +@(private) sha256_k := [64]u32 { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, @@ -514,6 +518,7 @@ sha256_k := [64]u32 { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, } +@(private) sha512_k := [80]u64 { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, @@ -557,70 +562,67 @@ sha512_k := [80]u64 { 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, } +@(private) SHA256_CH :: #force_inline proc "contextless" (x, y, z: u32) -> u32 { return (x & y) ~ (~x & z) } +@(private) SHA256_MAJ :: #force_inline proc "contextless" (x, y, z: u32) -> u32 { return (x & y) ~ (x & z) ~ (y & z) } +@(private) SHA512_CH :: #force_inline proc "contextless" (x, y, z: u64) -> u64 { return (x & y) ~ (~x & z) } +@(private) SHA512_MAJ :: #force_inline proc "contextless" (x, y, z: u64) -> u64 { return (x & y) ~ (x & z) ~ (y & z) } +@(private) SHA256_F1 :: #force_inline proc "contextless" (x: u32) -> u32 { - return util.ROTR32(x, 2) ~ util.ROTR32(x, 13) ~ util.ROTR32(x, 22) + return bits.rotate_left32(x, 30) ~ bits.rotate_left32(x, 19) ~ bits.rotate_left32(x, 10) } +@(private) SHA256_F2 :: #force_inline proc "contextless" (x: u32) -> u32 { - return util.ROTR32(x, 6) ~ util.ROTR32(x, 11) ~ util.ROTR32(x, 25) + return bits.rotate_left32(x, 26) ~ bits.rotate_left32(x, 21) ~ bits.rotate_left32(x, 7) } +@(private) SHA256_F3 :: #force_inline proc "contextless" (x: u32) -> u32 { - return util.ROTR32(x, 7) ~ util.ROTR32(x, 18) ~ (x >> 3) + return bits.rotate_left32(x, 25) ~ bits.rotate_left32(x, 14) ~ (x >> 3) } +@(private) SHA256_F4 :: #force_inline proc "contextless" (x: u32) -> u32 { - return util.ROTR32(x, 17) ~ util.ROTR32(x, 19) ~ (x >> 10) + return bits.rotate_left32(x, 15) ~ bits.rotate_left32(x, 13) ~ (x >> 10) } +@(private) SHA512_F1 :: #force_inline proc "contextless" (x: u64) -> u64 { - return util.ROTR64(x, 28) ~ util.ROTR64(x, 34) ~ util.ROTR64(x, 39) + return bits.rotate_left64(x, 36) ~ bits.rotate_left64(x, 30) ~ bits.rotate_left64(x, 25) } +@(private) SHA512_F2 :: #force_inline proc "contextless" (x: u64) -> u64 { - return util.ROTR64(x, 14) ~ util.ROTR64(x, 18) ~ util.ROTR64(x, 41) + return bits.rotate_left64(x, 50) ~ bits.rotate_left64(x, 46) ~ bits.rotate_left64(x, 23) } +@(private) SHA512_F3 :: #force_inline proc "contextless" (x: u64) -> u64 { - return util.ROTR64(x, 1) ~ util.ROTR64(x, 8) ~ (x >> 7) + return bits.rotate_left64(x, 63) ~ bits.rotate_left64(x, 56) ~ (x >> 7) } +@(private) SHA512_F4 :: #force_inline proc "contextless" (x: u64) -> u64 { - return util.ROTR64(x, 19) ~ util.ROTR64(x, 61) ~ (x >> 6) -} - -PACK32 :: #force_inline proc "contextless" (b: []byte, x: ^u32) { - x^ = u32(b[3]) | u32(b[2]) << 8 | u32(b[1]) << 16 | u32(b[0]) << 24 -} - -PACK64 :: #force_inline proc "contextless" (b: []byte, x: ^u64) { - x^ = - u64(b[7]) | - u64(b[6]) << 8 | - u64(b[5]) << 16 | - u64(b[4]) << 24 | - u64(b[3]) << 32 | - u64(b[2]) << 40 | - u64(b[1]) << 48 | - u64(b[0]) << 56 + return bits.rotate_left64(x, 45) ~ bits.rotate_left64(x, 3) ~ (x >> 6) } +@(private) sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { when T == Sha256_Context { w: [64]u32 @@ -644,9 +646,9 @@ sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { for j = 0; j < 16; j += 1 { when T == Sha256_Context { - PACK32(sub_block[j << 2:], &w[j]) + w[j] = endian.unchecked_get_u32be(sub_block[j << 2:]) } else when T == Sha512_Context { - PACK64(sub_block[j << 3:], &w[j]) + w[j] = endian.unchecked_get_u64be(sub_block[j << 3:]) } } From 7c1119f21727a359dd3c46d0cd3f3df1fb70b4eb Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 00:29:30 +0900 Subject: [PATCH 079/160] core/crypto/_sha3: Cleanups - Use `math/bits` --- core/crypto/_sha3/sha3.odin | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/core/crypto/_sha3/sha3.odin b/core/crypto/_sha3/sha3.odin index a56dce097..f66ed09e3 100644 --- a/core/crypto/_sha3/sha3.odin +++ b/core/crypto/_sha3/sha3.odin @@ -11,7 +11,7 @@ package _sha3 To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding. */ -import "../util" +import "core:math/bits" ROUNDS :: 24 @@ -38,7 +38,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) { 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, } - keccakf_rotc := [?]i32 { + keccakf_rotc := [?]int { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, } @@ -53,18 +53,8 @@ keccakf :: proc "contextless" (st: ^[25]u64) { bc: [5]u64 = --- when ODIN_ENDIAN != .Little { - v: uintptr = --- for i = 0; i < 25; i += 1 { - v := uintptr(&st[i]) - st[i] = - u64((^u8)(v + 0)^ << 0) | - u64((^u8)(v + 1)^ << 8) | - u64((^u8)(v + 2)^ << 16) | - u64((^u8)(v + 3)^ << 24) | - u64((^u8)(v + 4)^ << 32) | - u64((^u8)(v + 5)^ << 40) | - u64((^u8)(v + 6)^ << 48) | - u64((^u8)(v + 7)^ << 56) + st[i] = bits.byte_swap(st[i]) } } @@ -75,7 +65,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) { } for i = 0; i < 5; i += 1 { - t = bc[(i + 4) % 5] ~ util.ROTL64(bc[(i + 1) % 5], 1) + t = bc[(i + 4) % 5] ~ bits.rotate_left64(bc[(i + 1) % 5], 1) for j = 0; j < 25; j += 5 { st[j + i] ~= t } @@ -86,7 +76,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) { for i = 0; i < 24; i += 1 { j = keccakf_piln[i] bc[0] = st[j] - st[j] = util.ROTL64(t, u64(keccakf_rotc[i])) + st[j] = bits.rotate_left64(t, keccakf_rotc[i]) t = bc[0] } @@ -105,16 +95,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) { when ODIN_ENDIAN != .Little { for i = 0; i < 25; i += 1 { - v = uintptr(&st[i]) - t = st[i] - (^u8)(v + 0)^ = (t >> 0) & 0xff - (^u8)(v + 1)^ = (t >> 8) & 0xff - (^u8)(v + 2)^ = (t >> 16) & 0xff - (^u8)(v + 3)^ = (t >> 24) & 0xff - (^u8)(v + 4)^ = (t >> 32) & 0xff - (^u8)(v + 5)^ = (t >> 40) & 0xff - (^u8)(v + 6)^ = (t >> 48) & 0xff - (^u8)(v + 7)^ = (t >> 56) & 0xff + st[i] = bits.byte_swap(st[i]) } } } @@ -124,6 +105,7 @@ init :: proc "contextless" (c: ^Sha3_Context) { c.st.q[i] = 0 } c.rsiz = 200 - 2 * c.mdlen + c.pt = 0 } update :: proc "contextless" (c: ^Sha3_Context, data: []byte) { From a162b515889e6aa291e82ed1b0f4d01d4b13a4a2 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 10:08:51 +0900 Subject: [PATCH 080/160] core/crypto/siphash: Cleanups - Use `encoding/endian` - Use `math/bits` - Add `@(private)` annotations to internals - Minor optimization --- core/crypto/siphash/siphash.odin | 31 +++++++++++++++---------------- vendor/botan/siphash/siphash.odin | 8 ++++---- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin index ef0c68ad3..232da8b68 100644 --- a/core/crypto/siphash/siphash.odin +++ b/core/crypto/siphash/siphash.odin @@ -13,7 +13,8 @@ package siphash */ import "core:crypto" -import "core:crypto/util" +import "core:encoding/endian" +import "core:math/bits" /* High level API @@ -236,8 +237,8 @@ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) { is_valid_setting, "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)", ) - ctx.k0 = util.U64_LE(key[:8]) - ctx.k1 = util.U64_LE(key[8:]) + ctx.k0 = endian.unchecked_get_u64le(key[:8]) + ctx.k1 = endian.unchecked_get_u64le(key[8:]) ctx.v0 = 0x736f6d6570736575 ~ ctx.k0 ctx.v1 = 0x646f72616e646f6d ~ ctx.k1 ctx.v2 = 0x6c7967656e657261 ~ ctx.k0 @@ -252,13 +253,8 @@ update :: proc(ctx: ^Context, data: []byte) { i := 0 m: u64 for i < ctx.last_block { - m = u64(ctx.buf[i] & 0xff) - i += 1 - - for r in u64(1) ..< 8 { - m |= u64(ctx.buf[i] & 0xff) << (r * 8) - i += 1 - } + m = endian.unchecked_get_u64le(ctx.buf[i:]) + i += 8 ctx.v3 ~= m for _ in 0 ..< ctx.c_rounds { @@ -315,10 +311,12 @@ Context :: struct { is_initialized: bool, } +@(private) _get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte { return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3)) } +@(private) _collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) { dst[0] = _get_byte(7, hash) dst[1] = _get_byte(6, hash) @@ -330,19 +328,20 @@ _collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) { dst[7] = _get_byte(0, hash) } +@(private) _compress :: #force_inline proc "contextless" (ctx: ^Context) { ctx.v0 += ctx.v1 - ctx.v1 = util.ROTL64(ctx.v1, 13) + ctx.v1 = bits.rotate_left64(ctx.v1, 13) ctx.v1 ~= ctx.v0 - ctx.v0 = util.ROTL64(ctx.v0, 32) + ctx.v0 = bits.rotate_left64(ctx.v0, 32) ctx.v2 += ctx.v3 - ctx.v3 = util.ROTL64(ctx.v3, 16) + ctx.v3 = bits.rotate_left64(ctx.v3, 16) ctx.v3 ~= ctx.v2 ctx.v0 += ctx.v3 - ctx.v3 = util.ROTL64(ctx.v3, 21) + ctx.v3 = bits.rotate_left64(ctx.v3, 21) ctx.v3 ~= ctx.v0 ctx.v2 += ctx.v1 - ctx.v1 = util.ROTL64(ctx.v1, 17) + ctx.v1 = bits.rotate_left64(ctx.v1, 17) ctx.v1 ~= ctx.v2 - ctx.v2 = util.ROTL64(ctx.v2, 32) + ctx.v2 = bits.rotate_left64(ctx.v2, 32) } diff --git a/vendor/botan/siphash/siphash.odin b/vendor/botan/siphash/siphash.odin index 81ac71cd5..84935e240 100644 --- a/vendor/botan/siphash/siphash.odin +++ b/vendor/botan/siphash/siphash.odin @@ -14,7 +14,7 @@ package vendor_siphash */ import "core:crypto" -import "core:crypto/util" +import "core:encoding/endian" import botan "../bindings" @@ -35,7 +35,7 @@ sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 { init(&ctx, key[:], 1, 3) update(&ctx, msg[:]) final(&ctx, dst[:]) - return util.U64_LE(dst[:]) + return endian.unchecked_get_u64le(dst[:]) } // sum_string_to_buffer_1_3 will hash the given message with the key and write @@ -94,7 +94,7 @@ sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 { init(&ctx, key[:]) update(&ctx, msg[:]) final(&ctx, dst[:]) - return util.U64_LE(dst[:]) + return endian.unchecked_get_u64le(dst[:]) } // sum_string_to_buffer_2_4 will hash the given message with the key and write @@ -172,7 +172,7 @@ sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 { init(&ctx, key[:], 4, 8) update(&ctx, msg[:]) final(&ctx, dst[:]) - return util.U64_LE(dst[:]) + return endian.unchecked_get_u64le(dst[:]) } // sum_string_to_buffer_4_8 will hash the given message with the key and write From b71d3c739a78091a35ce7bcadf52b6d6049222d0 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 10:42:56 +0900 Subject: [PATCH 081/160] core/crypto/sm3: Cleanups - Use `encoding/endian` - Use `math/bits` - Add `@(private)` annotations to internals --- core/crypto/sm3/sm3.odin | 78 +++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index 017cf2246..d12b254f7 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -10,11 +10,11 @@ package sm3 Implementation of the SM3 hashing algorithm, as defined in */ +import "core:encoding/endian" import "core:io" +import "core:math/bits" import "core:os" -import "../util" - /* High level API */ @@ -110,6 +110,9 @@ init :: proc(ctx: ^Sm3_Context) { ctx.state[5] = IV[5] ctx.state[6] = IV[6] ctx.state[7] = IV[7] + + ctx.length = 0 + ctx.bitlength = 0 } update :: proc(ctx: ^Sm3_Context, data: []byte) { @@ -119,14 +122,14 @@ update :: proc(ctx: ^Sm3_Context, data: []byte) { if ctx.bitlength > 0 { n := copy(ctx.x[ctx.bitlength:], data[:]) ctx.bitlength += u64(n) - if ctx.bitlength == 64 { + if ctx.bitlength == BLOCK_SIZE { block(ctx, ctx.x[:]) ctx.bitlength = 0 } data = data[n:] } - if len(data) >= 64 { - n := len(data) &~ (64 - 1) + if len(data) >= BLOCK_SIZE { + n := len(data) &~ (BLOCK_SIZE - 1) block(ctx, data[:n]) data = data[n:] } @@ -138,45 +141,44 @@ update :: proc(ctx: ^Sm3_Context, data: []byte) { final :: proc(ctx: ^Sm3_Context, hash: []byte) { length := ctx.length - pad: [64]byte + pad: [BLOCK_SIZE]byte pad[0] = 0x80 - if length % 64 < 56 { - update(ctx, pad[0:56 - length % 64]) + if length % BLOCK_SIZE < 56 { + update(ctx, pad[0:56 - length % BLOCK_SIZE]) } else { - update(ctx, pad[0:64 + 56 - length % 64]) + update(ctx, pad[0:BLOCK_SIZE + 56 - length % BLOCK_SIZE]) } length <<= 3 - util.PUT_U64_BE(pad[:], length) + endian.unchecked_put_u64be(pad[:], length) update(ctx, pad[0:8]) assert(ctx.bitlength == 0) - util.PUT_U32_BE(hash[0:], ctx.state[0]) - util.PUT_U32_BE(hash[4:], ctx.state[1]) - util.PUT_U32_BE(hash[8:], ctx.state[2]) - util.PUT_U32_BE(hash[12:], ctx.state[3]) - util.PUT_U32_BE(hash[16:], ctx.state[4]) - util.PUT_U32_BE(hash[20:], ctx.state[5]) - util.PUT_U32_BE(hash[24:], ctx.state[6]) - util.PUT_U32_BE(hash[28:], ctx.state[7]) + for i := 0; i < DIGEST_SIZE / 4; i += 1 { + endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i]) + } } /* SM3 implementation */ +BLOCK_SIZE :: 64 + Sm3_Context :: struct { state: [8]u32, - x: [64]byte, + x: [BLOCK_SIZE]byte, bitlength: u64, length: u64, } +@(private) IV := [8]u32 { 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e, } +@(private) block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { buf := buf @@ -186,20 +188,18 @@ block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { state0, state1, state2, state3 := ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] state4, state5, state6, state7 := ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] - for len(buf) >= 64 { + for len(buf) >= BLOCK_SIZE { for i := 0; i < 16; i += 1 { - j := i * 4 - w[i] = - u32(buf[j]) << 24 | u32(buf[j + 1]) << 16 | u32(buf[j + 2]) << 8 | u32(buf[j + 3]) + w[i] = endian.unchecked_get_u32be(buf[i * 4:]) } for i := 16; i < 68; i += 1 { - p1v := w[i - 16] ~ w[i - 9] ~ util.ROTL32(w[i - 3], 15) + p1v := w[i - 16] ~ w[i - 9] ~ bits.rotate_left32(w[i - 3], 15) // @note(zh): inlined P1 w[i] = p1v ~ - util.ROTL32(p1v, 15) ~ - util.ROTL32(p1v, 23) ~ - util.ROTL32(w[i - 13], 7) ~ + bits.rotate_left32(p1v, 15) ~ + bits.rotate_left32(p1v, 23) ~ + bits.rotate_left32(w[i - 13], 7) ~ w[i - 6] } for i := 0; i < 64; i += 1 { @@ -210,8 +210,8 @@ block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { e, f, g, h := state4, state5, state6, state7 for i := 0; i < 16; i += 1 { - v1 := util.ROTL32(u32(a), 12) - ss1 := util.ROTL32(v1 + u32(e) + util.ROTL32(0x79cc4519, i), 7) + v1 := bits.rotate_left32(u32(a), 12) + ss1 := bits.rotate_left32(v1 + u32(e) + bits.rotate_left32(0x79cc4519, i), 7) ss2 := ss1 ~ v1 // @note(zh): inlined FF1 @@ -219,15 +219,18 @@ block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { // @note(zh): inlined GG1 tt2 := u32(e ~ f ~ g) + u32(h) + ss1 + w[i] - a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c + a, b, c, d = tt1, a, bits.rotate_left32(u32(b), 9), c // @note(zh): inlined P0 e, f, g, h = - (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g + (tt2 ~ bits.rotate_left32(tt2, 9) ~ bits.rotate_left32(tt2, 17)), + e, + bits.rotate_left32(u32(f), 19), + g } for i := 16; i < 64; i += 1 { - v := util.ROTL32(u32(a), 12) - ss1 := util.ROTL32(v + u32(e) + util.ROTL32(0x7a879d8a, i % 32), 7) + v := bits.rotate_left32(u32(a), 12) + ss1 := bits.rotate_left32(v + u32(e) + bits.rotate_left32(0x7a879d8a, i % 32), 7) ss2 := ss1 ~ v // @note(zh): inlined FF2 @@ -235,10 +238,13 @@ block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { // @note(zh): inlined GG2 tt2 := u32(((e & f) | ((~e) & g)) + h) + ss1 + w[i] - a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c + a, b, c, d = tt1, a, bits.rotate_left32(u32(b), 9), c // @note(zh): inlined P0 e, f, g, h = - (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g + (tt2 ~ bits.rotate_left32(tt2, 9) ~ bits.rotate_left32(tt2, 17)), + e, + bits.rotate_left32(u32(f), 19), + g } state0 ~= a @@ -250,7 +256,7 @@ block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { state6 ~= g state7 ~= h - buf = buf[64:] + buf = buf[BLOCK_SIZE:] } ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] = state0, state1, state2, state3 From 31b42a53fc9b2b191789d71e8c686cf3d4553a29 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 10:58:32 +0900 Subject: [PATCH 082/160] core/crypto/siphash: Fix the low-level API The `update` and `final` routines were written with the assumption that update will only be called once, and that the underlying data does not change between the calls. --- core/crypto/siphash/siphash.odin | 76 +++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin index 232da8b68..ab6532e4d 100644 --- a/core/crypto/siphash/siphash.odin +++ b/core/crypto/siphash/siphash.odin @@ -243,43 +243,45 @@ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) { ctx.v1 = 0x646f72616e646f6d ~ ctx.k1 ctx.v2 = 0x6c7967656e657261 ~ ctx.k0 ctx.v3 = 0x7465646279746573 ~ ctx.k1 + + ctx.last_block = 0 + ctx.total_length = 0 + ctx.is_initialized = true } update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized, "crypto/siphash: Context is not initialized") - ctx.last_block = len(data) / 8 * 8 - ctx.buf = data - i := 0 - m: u64 - for i < ctx.last_block { - m = endian.unchecked_get_u64le(ctx.buf[i:]) - i += 8 + assert(ctx.is_initialized, "crypto/siphash: context is not initialized") - ctx.v3 ~= m - for _ in 0 ..< ctx.c_rounds { - _compress(ctx) + data := data + ctx.total_length += len(data) + if ctx.last_block > 0 { + n := copy(ctx.buf[ctx.last_block:], data) + ctx.last_block += n + if ctx.last_block == BLOCK_SIZE { + block(ctx, ctx.buf[:]) + ctx.last_block = 0 } - - ctx.v0 ~= m + data = data[n:] + } + if len(data) >= BLOCK_SIZE { + n := len(data) &~ (BLOCK_SIZE - 1) + block(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.last_block = copy(ctx.buf[:], data) } } final :: proc(ctx: ^Context, dst: ^u64) { - m: u64 - for i := len(ctx.buf) - 1; i >= ctx.last_block; i -= 1 { - m <<= 8 - m |= u64(ctx.buf[i] & 0xff) - } - m |= u64(len(ctx.buf) << 56) + assert(ctx.is_initialized, "crypto/siphash: context is not initialized") - ctx.v3 ~= m + tmp: [BLOCK_SIZE]byte + copy(tmp[:], ctx.buf[:ctx.last_block]) + tmp[7] = byte(ctx.total_length & 0xff) + block(ctx, tmp[:]) - for _ in 0 ..< ctx.c_rounds { - _compress(ctx) - } - - ctx.v0 ~= m ctx.v2 ~= 0xff for _ in 0 ..< ctx.d_rounds { @@ -296,21 +298,43 @@ reset :: proc(ctx: ^Context) { ctx.v0, ctx.v1 = 0, 0 ctx.v2, ctx.v3 = 0, 0 ctx.last_block = 0 + ctx.total_length = 0 ctx.c_rounds = 0 ctx.d_rounds = 0 ctx.is_initialized = false } +BLOCK_SIZE :: 8 + Context :: struct { v0, v1, v2, v3: u64, // State values k0, k1: u64, // Split key c_rounds: int, // Number of message rounds d_rounds: int, // Number of finalization rounds - buf: []byte, // Provided data + buf: [BLOCK_SIZE]byte, // Provided data last_block: int, // Offset from the last block + total_length: int, is_initialized: bool, } +@(private) +block :: proc "contextless" (ctx: ^Context, buf: []byte) { + buf := buf + + for len(buf) >= BLOCK_SIZE { + m := endian.unchecked_get_u64le(buf) + + ctx.v3 ~= m + for _ in 0 ..< ctx.c_rounds { + _compress(ctx) + } + + ctx.v0 ~= m + + buf = buf[BLOCK_SIZE:] + } +} + @(private) _get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte { return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3)) From e3a836f93c21b1a6da4cdec411b55c5886b778da Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 12:32:20 +0900 Subject: [PATCH 083/160] core/crypto/sha2: Fix `hash_stream_224` and `hash_stream_256` --- core/crypto/sha2/sha2.odin | 49 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index a63f55476..7f87c4aa2 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -37,7 +37,7 @@ hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { hash: [DIGEST_SIZE_224]byte ctx: Sha256_Context - ctx.is224 = true + ctx.md_bits = 224 init(&ctx) update(&ctx, data) final(&ctx, hash[:]) @@ -60,7 +60,7 @@ hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { "Size of destination buffer is smaller than the digest size", ) ctx: Sha256_Context - ctx.is224 = true + ctx.md_bits = 224 init(&ctx) update(&ctx, data) final(&ctx, hash) @@ -70,8 +70,8 @@ hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { hash: [DIGEST_SIZE_224]byte - ctx: Sha512_Context - ctx.is384 = false + ctx: Sha256_Context + ctx.md_bits = 224 init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -119,7 +119,7 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte ctx: Sha256_Context - ctx.is224 = false + ctx.md_bits = 256 init(&ctx) update(&ctx, data) final(&ctx, hash[:]) @@ -142,7 +142,7 @@ hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { "Size of destination buffer is smaller than the digest size", ) ctx: Sha256_Context - ctx.is224 = false + ctx.md_bits = 256 init(&ctx) update(&ctx, data) final(&ctx, hash) @@ -152,8 +152,8 @@ hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: Sha512_Context - ctx.is384 = false + ctx: Sha256_Context + ctx.md_bits = 256 init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -201,7 +201,7 @@ hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { hash: [DIGEST_SIZE_384]byte ctx: Sha512_Context - ctx.is384 = true + ctx.md_bits = 384 init(&ctx) update(&ctx, data) final(&ctx, hash[:]) @@ -224,7 +224,7 @@ hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { "Size of destination buffer is smaller than the digest size", ) ctx: Sha512_Context - ctx.is384 = true + ctx.md_bits = 384 init(&ctx) update(&ctx, data) final(&ctx, hash) @@ -235,7 +235,7 @@ hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { hash: [DIGEST_SIZE_384]byte ctx: Sha512_Context - ctx.is384 = true + ctx.md_bits = 384 init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -283,7 +283,7 @@ hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { hash: [DIGEST_SIZE_512]byte ctx: Sha512_Context - ctx.is384 = false + ctx.md_bits = 512 init(&ctx) update(&ctx, data) final(&ctx, hash[:]) @@ -306,7 +306,7 @@ hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { "Size of destination buffer is smaller than the digest size", ) ctx: Sha512_Context - ctx.is384 = false + ctx.md_bits = 512 init(&ctx) update(&ctx, data) final(&ctx, hash) @@ -317,7 +317,7 @@ hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { hash: [DIGEST_SIZE_512]byte ctx: Sha512_Context - ctx.is384 = false + ctx.md_bits = 512 init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -360,7 +360,7 @@ hash_512 :: proc { init :: proc(ctx: ^$T) { when T == Sha256_Context { - if ctx.is224 { + if ctx.md_bits == 224 { ctx.h[0] = 0xc1059ed8 ctx.h[1] = 0x367cd507 ctx.h[2] = 0x3070dd17 @@ -380,7 +380,7 @@ init :: proc(ctx: ^$T) { ctx.h[7] = 0x5be0cd19 } } else when T == Sha512_Context { - if ctx.is384 { + if ctx.md_bits == 384 { ctx.h[0] = 0xcbbb9d5dc1059ed8 ctx.h[1] = 0x629a292a367cd507 ctx.h[2] = 0x9159015a3070dd17 @@ -444,7 +444,6 @@ update :: proc(ctx: ^$T, data: []byte) { final :: proc(ctx: ^$T, hash: []byte) { block_nb, pm_len, len_b: u32 - i: i32 when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} @@ -461,16 +460,12 @@ final :: proc(ctx: ^$T, hash: []byte) { sha2_transf(ctx, ctx.block[:], uint(block_nb)) when T == Sha256_Context { - if ctx.is224 { - for i = 0; i < 7; i += 1 {endian.unchecked_put_u32be(hash[i << 2:], ctx.h[i])} - } else { - for i = 0; i < 8; i += 1 {endian.unchecked_put_u32be(hash[i << 2:], ctx.h[i])} + for i := 0; i < ctx.md_bits / 32; i += 1 { + endian.unchecked_put_u32be(hash[i * 4:], ctx.h[i]) } } else when T == Sha512_Context { - if ctx.is384 { - for i = 0; i < 6; i += 1 {endian.unchecked_put_u64be(hash[i << 3:], ctx.h[i])} - } else { - for i = 0; i < 8; i += 1 {endian.unchecked_put_u64be(hash[i << 3:], ctx.h[i])} + for i := 0; i < ctx.md_bits / 64; i += 1 { + endian.unchecked_put_u64be(hash[i * 8:], ctx.h[i]) } } } @@ -487,7 +482,7 @@ Sha256_Context :: struct { length: uint, block: [128]byte, h: [8]u32, - is224: bool, + md_bits: int, } Sha512_Context :: struct { @@ -495,7 +490,7 @@ Sha512_Context :: struct { length: uint, block: [256]byte, h: [8]u64, - is384: bool, + md_bits: int, } @(private) From e86bb3a7955b4ab116ce427c6beb99f3053c40ec Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 12:51:49 +0900 Subject: [PATCH 084/160] core/crypto: Change hash asserts to panics Assertions can be disabled, but at the point where cryptographic anything is involved, a single branch has an infinitesimally small performance impact. The correct thing to do is to punch the caller in the face if they do something that is blatantly incorrect, especially in a security critical setting. --- core/crypto/_blake2/blake2.odin | 8 +++++++- core/crypto/_sha3/sha3.odin | 8 +++++++- core/crypto/blake2b/blake2b.odin | 3 +-- core/crypto/blake2s/blake2s.odin | 3 +-- core/crypto/keccak/keccak.odin | 18 +----------------- core/crypto/md5/md5.odin | 5 ++++- core/crypto/sha1/sha1.odin | 5 ++++- core/crypto/sha2/sha2.odin | 20 ++++---------------- core/crypto/sha3/sha3.odin | 18 +----------------- core/crypto/shake/shake.odin | 8 -------- core/crypto/siphash/siphash.odin | 28 ++++++++++------------------ core/crypto/sm3/sm3.odin | 5 ++++- 12 files changed, 44 insertions(+), 85 deletions(-) diff --git a/core/crypto/_blake2/blake2.odin b/core/crypto/_blake2/blake2.odin index c1b5c5dad..a522a390e 100644 --- a/core/crypto/_blake2/blake2.odin +++ b/core/crypto/_blake2/blake2.odin @@ -180,11 +180,17 @@ update :: proc "contextless" (ctx: ^$T, p: []byte) { ctx.nx += copy(ctx.x[ctx.nx:], p) } -final :: proc "contextless" (ctx: ^$T, hash: []byte) { +final :: proc(ctx: ^$T, hash: []byte) { when T == Blake2s_Context { + if len(hash) < BLAKE2S_SIZE { + panic("crypto/blake2s: invalid destination digest size") + } blake2s_final(ctx, hash) } when T == Blake2b_Context { + if len(hash) < BLAKE2B_SIZE { + panic("crypto/blake2b: invalid destination digest size") + } blake2b_final(ctx, hash) } } diff --git a/core/crypto/_sha3/sha3.odin b/core/crypto/_sha3/sha3.odin index f66ed09e3..917a763c1 100644 --- a/core/crypto/_sha3/sha3.odin +++ b/core/crypto/_sha3/sha3.odin @@ -121,7 +121,13 @@ update :: proc "contextless" (c: ^Sha3_Context, data: []byte) { c.pt = j } -final :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { +final :: proc(c: ^Sha3_Context, hash: []byte) { + if len(hash) < c.mdlen { + if c.is_keccak { + panic("crypto/keccac: invalid destination digest size") + } + panic("crypto/sha3: invalid destination digest size") + } if c.is_keccak { c.st.b[c.pt] ~= 0x01 } else { diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index caa1758fe..17e40ad9c 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -53,7 +53,6 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") ctx: _blake2.Blake2b_Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2B_SIZE @@ -122,6 +121,6 @@ update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) { _blake2.update(ctx, data) } -final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) { +final :: proc(ctx: ^_blake2.Blake2b_Context, hash: []byte) { _blake2.final(ctx, hash) } diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index db9dcab38..1f607ffdd 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -54,7 +54,6 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") ctx: _blake2.Blake2s_Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2S_SIZE @@ -122,6 +121,6 @@ update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) { _blake2.update(ctx, data) } -final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) { +final :: proc(ctx: ^_blake2.Blake2s_Context, hash: []byte) { _blake2.final(ctx, hash) } diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index fc9131fa3..6e63af80f 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -56,10 +56,6 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_224, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_224 ctx.is_keccak = true @@ -141,10 +137,6 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_256, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_256 ctx.is_keccak = true @@ -226,10 +218,6 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_384, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_384 ctx.is_keccak = true @@ -311,10 +299,6 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_512, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_512 ctx.is_keccak = true @@ -381,6 +365,6 @@ update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { _sha3.update(ctx, data) } -final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { +final :: proc(ctx: ^_sha3.Sha3_Context, hash: []byte) { _sha3.final(ctx, hash) } diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index e451afd20..05602c249 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -50,7 +50,6 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") ctx: Md5_Context init(&ctx) update(&ctx, data) @@ -125,6 +124,10 @@ update :: proc(ctx: ^Md5_Context, data: []byte) { } final :: proc(ctx: ^Md5_Context, hash: []byte) { + if len(hash) < DIGEST_SIZE { + panic("crypto/md5: invalid destination digest size") + } + i := ctx.datalen if ctx.datalen < 56 { diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index c2cee8098..0d85a61f9 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -50,7 +50,6 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") ctx: Sha1_Context init(&ctx) update(&ctx, data) @@ -130,6 +129,10 @@ update :: proc(ctx: ^Sha1_Context, data: []byte) { } final :: proc(ctx: ^Sha1_Context, hash: []byte) { + if len(hash) < DIGEST_SIZE { + panic("crypto/sha1: invalid destination digest size") + } + i := ctx.datalen if ctx.datalen < 56 { diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 7f87c4aa2..47ede9cf4 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -55,10 +55,6 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_224, - "Size of destination buffer is smaller than the digest size", - ) ctx: Sha256_Context ctx.md_bits = 224 init(&ctx) @@ -137,10 +133,6 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_256, - "Size of destination buffer is smaller than the digest size", - ) ctx: Sha256_Context ctx.md_bits = 256 init(&ctx) @@ -219,10 +211,6 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_384, - "Size of destination buffer is smaller than the digest size", - ) ctx: Sha512_Context ctx.md_bits = 384 init(&ctx) @@ -301,10 +289,6 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_512, - "Size of destination buffer is smaller than the digest size", - ) ctx: Sha512_Context ctx.md_bits = 512 init(&ctx) @@ -445,6 +429,10 @@ update :: proc(ctx: ^$T, data: []byte) { final :: proc(ctx: ^$T, hash: []byte) { block_nb, pm_len, len_b: u32 + if len(hash) * 8 < ctx.md_bits { + panic("crypto/sha2: invalid destination digest size") + } + when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 6b7ad04a1..7dcaf211b 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -54,10 +54,6 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_224, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_224 _sha3.init(&ctx) @@ -136,10 +132,6 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_256, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_256 _sha3.init(&ctx) @@ -218,10 +210,6 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_384, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_384 _sha3.init(&ctx) @@ -300,10 +288,6 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_512, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_512 _sha3.init(&ctx) @@ -367,6 +351,6 @@ update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { _sha3.update(ctx, data) } -final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { +final :: proc(ctx: ^_sha3.Sha3_Context, hash: []byte) { _sha3.final(ctx, hash) } diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 70755069a..dc7eb3387 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -53,10 +53,6 @@ hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_128, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_128 _sha3.init(&ctx) @@ -138,10 +134,6 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert( - len(hash) >= DIGEST_SIZE_256, - "Size of destination buffer is smaller than the digest size", - ) ctx: _sha3.Sha3_Context ctx.mdlen = DIGEST_SIZE_256 _sha3.init(&ctx) diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin index ab6532e4d..c51e38ab0 100644 --- a/core/crypto/siphash/siphash.odin +++ b/core/crypto/siphash/siphash.odin @@ -49,10 +49,6 @@ sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) { // sum_bytes_to_buffer_1_3 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) { - assert( - len(dst) >= DIGEST_SIZE, - "crypto/siphash: Destination buffer needs to be at least of size 8", - ) hash := sum_bytes_1_3(msg, key) _collect_output(dst[:], hash) } @@ -109,10 +105,6 @@ sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) { // sum_bytes_to_buffer_2_4 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) { - assert( - len(dst) >= DIGEST_SIZE, - "crypto/siphash: Destination buffer needs to be at least of size 8", - ) hash := sum_bytes_2_4(msg, key) _collect_output(dst[:], hash) } @@ -187,10 +179,6 @@ sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) { // sum_bytes_to_buffer_4_8 will hash the given message with the key and write // the computed hash into the provided destination buffer sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) { - assert( - len(dst) >= DIGEST_SIZE, - "crypto/siphash: Destination buffer needs to be at least of size 8", - ) hash := sum_bytes_4_8(msg, key) _collect_output(dst[:], hash) } @@ -226,17 +214,18 @@ verify_4_8 :: proc { */ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) { - assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16") + if len(key) != KEY_SIZE { + panic("crypto/siphash; invalid key size") + } ctx.c_rounds = c_rounds ctx.d_rounds = d_rounds is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) || (ctx.c_rounds == 2 && ctx.d_rounds == 4) || (ctx.c_rounds == 4 && ctx.d_rounds == 8) - assert( - is_valid_setting, - "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)", - ) + if !is_valid_setting { + panic("crypto/siphash: incorrect rounds set up") + } ctx.k0 = endian.unchecked_get_u64le(key[:8]) ctx.k1 = endian.unchecked_get_u64le(key[8:]) ctx.v0 = 0x736f6d6570736575 ~ ctx.k0 @@ -341,7 +330,10 @@ _get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byt } @(private) -_collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) { +_collect_output :: #force_inline proc(dst: []byte, hash: u64) { + if len(dst) < DIGEST_SIZE { + panic("crypto/siphash: invalid tag size") + } dst[0] = _get_byte(7, hash) dst[1] = _get_byte(6, hash) dst[2] = _get_byte(5, hash) diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index d12b254f7..4474af69b 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -49,7 +49,6 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") ctx: Sm3_Context init(&ctx) update(&ctx, data) @@ -139,6 +138,10 @@ update :: proc(ctx: ^Sm3_Context, data: []byte) { } final :: proc(ctx: ^Sm3_Context, hash: []byte) { + if len(hash) < DIGEST_SIZE { + panic("crypto/sm3: invalid destination digest size") + } + length := ctx.length pad: [BLOCK_SIZE]byte From 582bd760b7141e26242e55a376956568c14ff13b Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 12:57:28 +0900 Subject: [PATCH 085/160] core/crypto/shake: Add a TODO comment (NFC) --- core/crypto/shake/shake.odin | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index dc7eb3387..21f698db5 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -9,6 +9,9 @@ package shake Interface for the SHAKE hashing algorithm. The SHA3 functionality can be found in package sha3. + + TODO: This should provide an incremental squeeze interface, in addition + to the one-shot final call. */ import "core:io" From 71da3ef9255f6f66ff3124355fdf8c9d0b6ff9a7 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 13:26:03 +0900 Subject: [PATCH 086/160] core/crypto/sha2: Fix overflow for large amounts of hashed data --- core/crypto/sha2/sha2.odin | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 47ede9cf4..dd133fa5f 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -427,7 +427,8 @@ update :: proc(ctx: ^$T, data: []byte) { } final :: proc(ctx: ^$T, hash: []byte) { - block_nb, pm_len, len_b: u32 + block_nb, pm_len: uint + len_b: u64 if len(hash) * 8 < ctx.md_bits { panic("crypto/sha2: invalid destination digest size") @@ -437,15 +438,15 @@ final :: proc(ctx: ^$T, hash: []byte) { when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} - len_b = u32(ctx.tot_len + ctx.length) << 3 + len_b = u64(ctx.tot_len + ctx.length) << 3 when T == Sha256_Context {pm_len = block_nb << 6} else when T == Sha512_Context {pm_len = block_nb << 7} - mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length)) + mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(pm_len - ctx.length)) ctx.block[ctx.length] = 0x80 - endian.unchecked_put_u32be(ctx.block[pm_len - 4:], len_b) + endian.unchecked_put_u64be(ctx.block[pm_len - 8:], len_b) - sha2_transf(ctx, ctx.block[:], uint(block_nb)) + sha2_transf(ctx, ctx.block[:], block_nb) when T == Sha256_Context { for i := 0; i < ctx.md_bits / 32; i += 1 { From 70ba4b532176703b11d962e7e4f0bf0e85726c70 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 13:36:52 +0900 Subject: [PATCH 087/160] core/crypto: Add more assertions to the low level API Assertions here are "fine" and it matches what the code that has the checks in init/update/final already does. --- core/crypto/_blake2/blake2.odin | 14 +++++++++++++- core/crypto/_sha3/sha3.odin | 29 +++++++++++++++++++++++++---- core/crypto/blake2b/blake2b.odin | 2 +- core/crypto/blake2s/blake2s.odin | 2 +- core/crypto/keccak/keccak.odin | 2 +- core/crypto/md5/md5.odin | 10 ++++++++++ core/crypto/sha1/sha1.odin | 10 ++++++++++ core/crypto/sha2/sha2.odin | 12 ++++++++++++ core/crypto/sha3/sha3.odin | 2 +- core/crypto/shake/shake.odin | 4 ++-- core/crypto/sm3/sm3.odin | 10 ++++++++++ 11 files changed, 86 insertions(+), 11 deletions(-) diff --git a/core/crypto/_blake2/blake2.odin b/core/crypto/_blake2/blake2.odin index a522a390e..ce6f88f20 100644 --- a/core/crypto/_blake2/blake2.odin +++ b/core/crypto/_blake2/blake2.odin @@ -29,6 +29,8 @@ Blake2s_Context :: struct { size: byte, is_last_node: bool, cfg: Blake2_Config, + + is_initialized: bool, } Blake2b_Context :: struct { @@ -43,6 +45,8 @@ Blake2b_Context :: struct { size: byte, is_last_node: bool, cfg: Blake2_Config, + + is_initialized: bool, } Blake2_Config :: struct { @@ -152,9 +156,13 @@ init :: proc(ctx: ^$T) { } ctx.nx = 0 + + ctx.is_initialized = true } -update :: proc "contextless" (ctx: ^$T, p: []byte) { +update :: proc(ctx: ^$T, p: []byte) { + assert(ctx.is_initialized) + p := p when T == Blake2s_Context { block_size :: BLAKE2S_BLOCK_SIZE @@ -181,6 +189,8 @@ update :: proc "contextless" (ctx: ^$T, p: []byte) { } final :: proc(ctx: ^$T, hash: []byte) { + assert(ctx.is_initialized) + when T == Blake2s_Context { if len(hash) < BLAKE2S_SIZE { panic("crypto/blake2s: invalid destination digest size") @@ -193,6 +203,8 @@ final :: proc(ctx: ^$T, hash: []byte) { } blake2b_final(ctx, hash) } + + ctx.is_initialized = false } @(private) diff --git a/core/crypto/_sha3/sha3.odin b/core/crypto/_sha3/sha3.odin index 917a763c1..43af0ad75 100644 --- a/core/crypto/_sha3/sha3.odin +++ b/core/crypto/_sha3/sha3.odin @@ -24,6 +24,9 @@ Sha3_Context :: struct { rsiz: int, mdlen: int, is_keccak: bool, + + is_initialized: bool, + is_finalized: bool, // For SHAKE (unlimited squeeze is allowed) } keccakf :: proc "contextless" (st: ^[25]u64) { @@ -100,15 +103,21 @@ keccakf :: proc "contextless" (st: ^[25]u64) { } } -init :: proc "contextless" (c: ^Sha3_Context) { +init :: proc(c: ^Sha3_Context) { for i := 0; i < 25; i += 1 { c.st.q[i] = 0 } c.rsiz = 200 - 2 * c.mdlen c.pt = 0 + + c.is_initialized = true + c.is_finalized = false } -update :: proc "contextless" (c: ^Sha3_Context, data: []byte) { +update :: proc(c: ^Sha3_Context, data: []byte) { + assert(c.is_initialized) + assert(!c.is_finalized) + j := c.pt for i := 0; i < len(data); i += 1 { c.st.b[j] ~= data[i] @@ -122,6 +131,8 @@ update :: proc "contextless" (c: ^Sha3_Context, data: []byte) { } final :: proc(c: ^Sha3_Context, hash: []byte) { + assert(c.is_initialized) + if len(hash) < c.mdlen { if c.is_keccak { panic("crypto/keccac: invalid destination digest size") @@ -139,16 +150,26 @@ final :: proc(c: ^Sha3_Context, hash: []byte) { for i := 0; i < c.mdlen; i += 1 { hash[i] = c.st.b[i] } + + c.is_initialized = false // No more absorb, no more squeeze. } -shake_xof :: proc "contextless" (c: ^Sha3_Context) { +shake_xof :: proc(c: ^Sha3_Context) { + assert(c.is_initialized) + assert(!c.is_finalized) + c.st.b[c.pt] ~= 0x1F c.st.b[c.rsiz - 1] ~= 0x80 keccakf(&c.st.q) c.pt = 0 + + c.is_finalized = true // No more absorb, unlimited squeeze. } -shake_out :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { +shake_out :: proc(c: ^Sha3_Context, hash: []byte) { + assert(c.is_initialized) + assert(c.is_finalized) + j := c.pt for i := 0; i < len(hash); i += 1 { if j >= c.rsiz { diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index 17e40ad9c..476ecdeeb 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -117,7 +117,7 @@ init :: proc(ctx: ^_blake2.Blake2b_Context) { _blake2.init(ctx) } -update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) { +update :: proc(ctx: ^_blake2.Blake2b_Context, data: []byte) { _blake2.update(ctx, data) } diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index 1f607ffdd..f4d8eb804 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -117,7 +117,7 @@ init :: proc(ctx: ^_blake2.Blake2s_Context) { _blake2.init(ctx) } -update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) { +update :: proc(ctx: ^_blake2.Blake2s_Context, data: []byte) { _blake2.update(ctx, data) } diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index 6e63af80f..b8a071e8f 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -361,7 +361,7 @@ init :: proc(ctx: ^_sha3.Sha3_Context) { _sha3.init(ctx) } -update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { +update :: proc(ctx: ^_sha3.Sha3_Context, data: []byte) { _sha3.update(ctx, data) } diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index 05602c249..441e15a64 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -109,9 +109,13 @@ init :: proc(ctx: ^Md5_Context) { ctx.bitlen = 0 ctx.datalen = 0 + + ctx.is_initialized = true } update :: proc(ctx: ^Md5_Context, data: []byte) { + assert(ctx.is_initialized) + for i := 0; i < len(data); i += 1 { ctx.data[ctx.datalen] = data[i] ctx.datalen += 1 @@ -124,6 +128,8 @@ update :: proc(ctx: ^Md5_Context, data: []byte) { } final :: proc(ctx: ^Md5_Context, hash: []byte) { + assert(ctx.is_initialized) + if len(hash) < DIGEST_SIZE { panic("crypto/md5: invalid destination digest size") } @@ -155,6 +161,8 @@ final :: proc(ctx: ^Md5_Context, hash: []byte) { for i = 0; i < DIGEST_SIZE / 4; i += 1 { endian.unchecked_put_u32le(hash[i * 4:], ctx.state[i]) } + + ctx.is_initialized = false } /* @@ -168,6 +176,8 @@ Md5_Context :: struct { state: [4]u32, bitlen: u64, datalen: u32, + + is_initialized: bool, } /* diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index 0d85a61f9..e6da5b6b9 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -114,9 +114,13 @@ init :: proc(ctx: ^Sha1_Context) { ctx.datalen = 0 ctx.bitlen = 0 + + ctx.is_initialized = true } update :: proc(ctx: ^Sha1_Context, data: []byte) { + assert(ctx.is_initialized) + for i := 0; i < len(data); i += 1 { ctx.data[ctx.datalen] = data[i] ctx.datalen += 1 @@ -129,6 +133,8 @@ update :: proc(ctx: ^Sha1_Context, data: []byte) { } final :: proc(ctx: ^Sha1_Context, hash: []byte) { + assert(ctx.is_initialized) + if len(hash) < DIGEST_SIZE { panic("crypto/sha1: invalid destination digest size") } @@ -160,6 +166,8 @@ final :: proc(ctx: ^Sha1_Context, hash: []byte) { for i = 0; i < DIGEST_SIZE / 4; i += 1 { endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i]) } + + ctx.is_initialized = false } /* @@ -174,6 +182,8 @@ Sha1_Context :: struct { bitlen: u64, state: [5]u32, k: [4]u32, + + is_initialized: bool, } @(private) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index dd133fa5f..e44c31541 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -387,9 +387,13 @@ init :: proc(ctx: ^$T) { ctx.tot_len = 0 ctx.length = 0 + + ctx.is_initialized = true } update :: proc(ctx: ^$T, data: []byte) { + assert(ctx.is_initialized) + length := uint(len(data)) block_nb: uint new_len, rem_len, tmp_len: uint @@ -427,6 +431,8 @@ update :: proc(ctx: ^$T, data: []byte) { } final :: proc(ctx: ^$T, hash: []byte) { + assert(ctx.is_initialized) + block_nb, pm_len: uint len_b: u64 @@ -457,6 +463,8 @@ final :: proc(ctx: ^$T, hash: []byte) { endian.unchecked_put_u64be(hash[i * 8:], ctx.h[i]) } } + + ctx.is_initialized = false } /* @@ -472,6 +480,8 @@ Sha256_Context :: struct { block: [128]byte, h: [8]u32, md_bits: int, + + is_initialized: bool, } Sha512_Context :: struct { @@ -480,6 +490,8 @@ Sha512_Context :: struct { block: [256]byte, h: [8]u64, md_bits: int, + + is_initialized: bool, } @(private) diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 7dcaf211b..10a65e0b1 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -347,7 +347,7 @@ init :: proc(ctx: ^_sha3.Sha3_Context) { _sha3.init(ctx) } -update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { +update :: proc(ctx: ^_sha3.Sha3_Context, data: []byte) { _sha3.update(ctx, data) } diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 21f698db5..c490de41e 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -198,11 +198,11 @@ init :: proc(ctx: ^_sha3.Sha3_Context) { _sha3.init(ctx) } -update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { +update :: proc(ctx: ^_sha3.Sha3_Context, data: []byte) { _sha3.update(ctx, data) } -final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { +final :: proc(ctx: ^_sha3.Sha3_Context, hash: []byte) { _sha3.shake_xof(ctx) _sha3.shake_out(ctx, hash[:]) } diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index 4474af69b..943172482 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -112,9 +112,13 @@ init :: proc(ctx: ^Sm3_Context) { ctx.length = 0 ctx.bitlength = 0 + + ctx.is_initialized = true } update :: proc(ctx: ^Sm3_Context, data: []byte) { + assert(ctx.is_initialized) + data := data ctx.length += u64(len(data)) @@ -138,6 +142,8 @@ update :: proc(ctx: ^Sm3_Context, data: []byte) { } final :: proc(ctx: ^Sm3_Context, hash: []byte) { + assert(ctx.is_initialized) + if len(hash) < DIGEST_SIZE { panic("crypto/sm3: invalid destination digest size") } @@ -160,6 +166,8 @@ final :: proc(ctx: ^Sm3_Context, hash: []byte) { for i := 0; i < DIGEST_SIZE / 4; i += 1 { endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i]) } + + ctx.is_initialized = false } /* @@ -173,6 +181,8 @@ Sm3_Context :: struct { x: [BLOCK_SIZE]byte, bitlength: u64, length: u64, + + is_initialized: bool, } @(private) From 41fdcfeecfe0b82927f0a123aa91ea2d85136dae Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 20:44:10 +0900 Subject: [PATCH 088/160] core/crypto/sha2: Add SHA-512/256 --- core/crypto/sha2/sha2.odin | 107 ++++++++++++++++++++++-- tests/core/crypto/test_core_crypto.odin | 16 ++++ 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index e44c31541..d4b6b87bb 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -7,7 +7,7 @@ package sha2 List of contributors: zhibog, dotbmp: Initial implementation. - Implementation of the SHA2 hashing algorithm, as defined in + Implementation of the SHA2 hashing algorithm, as defined in and in RFC 3874 */ @@ -25,6 +25,7 @@ DIGEST_SIZE_224 :: 28 DIGEST_SIZE_256 :: 32 DIGEST_SIZE_384 :: 48 DIGEST_SIZE_512 :: 64 +DIGEST_SIZE_512_256 :: 32 // hash_string_224 will hash the given input and return the // computed hash @@ -338,13 +339,92 @@ hash_512 :: proc { hash_string_to_buffer_512, } +// hash_string_512_256 will hash the given input and return the +// computed hash +hash_string_512_256 :: proc(data: string) -> [DIGEST_SIZE_512_256]byte { + return hash_bytes_512_256(transmute([]byte)(data)) +} + +// hash_bytes_512_256 will hash the given input and return the +// computed hash +hash_bytes_512_256 :: proc(data: []byte) -> [DIGEST_SIZE_512_256]byte { + hash: [DIGEST_SIZE_512_256]byte + ctx: Sha512_Context + ctx.md_bits = 256 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash +} + +// hash_string_to_buffer_512_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512_256(transmute([]byte)(data), hash) +} + +// hash_bytes_to_buffer_512_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512_256 :: proc(data, hash: []byte) { + ctx: Sha512_Context + ctx.md_bits = 256 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + +// hash_stream_512_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512_256]byte, bool) { + hash: [DIGEST_SIZE_512_256]byte + ctx: Sha512_Context + ctx.md_bits = 256 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = io.read(s, buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true +} + +// hash_file_512_256 will read the file provided by the given handle +// and compute a hash +hash_file_512_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512_256]byte, bool) { + if !load_at_once { + return hash_stream_512_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512_256(buf[:]), ok + } + } + return [DIGEST_SIZE_512_256]byte{}, false +} + +hash_512_256 :: proc { + hash_stream_512_256, + hash_file_512_256, + hash_bytes_512_256, + hash_string_512_256, + hash_bytes_to_buffer_512_256, + hash_string_to_buffer_512_256, +} + /* Low level API */ init :: proc(ctx: ^$T) { when T == Sha256_Context { - if ctx.md_bits == 224 { + switch ctx.md_bits { + case 224: ctx.h[0] = 0xc1059ed8 ctx.h[1] = 0x367cd507 ctx.h[2] = 0x3070dd17 @@ -353,7 +433,7 @@ init :: proc(ctx: ^$T) { ctx.h[5] = 0x68581511 ctx.h[6] = 0x64f98fa7 ctx.h[7] = 0xbefa4fa4 - } else { + case 256: ctx.h[0] = 0x6a09e667 ctx.h[1] = 0xbb67ae85 ctx.h[2] = 0x3c6ef372 @@ -362,9 +442,23 @@ init :: proc(ctx: ^$T) { ctx.h[5] = 0x9b05688c ctx.h[6] = 0x1f83d9ab ctx.h[7] = 0x5be0cd19 + case: + panic("crypto/sha2: invalid digest output length") } } else when T == Sha512_Context { - if ctx.md_bits == 384 { + switch ctx.md_bits { + case 256: + // SHA-512/256 + ctx.h[0] = 0x22312194fc2bf72c + ctx.h[1] = 0x9f555fa3c84c64c2 + ctx.h[2] = 0x2393b86b6f53b151 + ctx.h[3] = 0x963877195940eabd + ctx.h[4] = 0x96283ee2a88effe3 + ctx.h[5] = 0xbe5e1e2553863992 + ctx.h[6] = 0x2b0199fc2c85b8aa + ctx.h[7] = 0x0eb72ddc81c52ca2 + case 384: + // SHA-384 ctx.h[0] = 0xcbbb9d5dc1059ed8 ctx.h[1] = 0x629a292a367cd507 ctx.h[2] = 0x9159015a3070dd17 @@ -373,7 +467,8 @@ init :: proc(ctx: ^$T) { ctx.h[5] = 0x8eb44a8768581511 ctx.h[6] = 0xdb0c2e0d64f98fa7 ctx.h[7] = 0x47b5481dbefa4fa4 - } else { + case 512: + // SHA-512 ctx.h[0] = 0x6a09e667f3bcc908 ctx.h[1] = 0xbb67ae8584caa73b ctx.h[2] = 0x3c6ef372fe94f82b @@ -382,6 +477,8 @@ init :: proc(ctx: ^$T) { ctx.h[5] = 0x9b05688c2b3e6c1f ctx.h[6] = 0x1f83d9abfb41bd6b ctx.h[7] = 0x5be0cd19137e2179 + case: + panic("crypto/sha2: invalid digest output length") } } diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index f6b4b10b8..ad1c5738d 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -71,6 +71,7 @@ main :: proc() { test_sha256(&t) test_sha384(&t) test_sha512(&t) + test_sha512_256(&t) test_sha3_224(&t) test_sha3_256(&t) test_sha3_384(&t) @@ -301,6 +302,21 @@ test_sha512 :: proc(t: ^testing.T) { } } +@(test) +test_sha512_256 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + test_vectors := [?]TestHash { + TestHash{"53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23", "abc"}, + TestHash{"3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_512_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + @(test) test_sha3_224 :: proc(t: ^testing.T) { // Test vectors from From 44c8da7bf203ff61cc2096eee82c6cba0c2ad138 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:27:13 +0900 Subject: [PATCH 089/160] core/crypto/blake: Remove, use BLAKE2b/BLAKE2s --- core/crypto/README.md | 1 - core/crypto/blake/blake.odin | 726 ------------------------ examples/all/all_main.odin | 2 - tests/core/crypto/test_core_crypto.odin | 61 -- 4 files changed, 790 deletions(-) delete mode 100644 core/crypto/blake/blake.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index dd594d5c2..3a8f81842 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -8,7 +8,6 @@ Please see the chart below for the options. ## Hashing algorithms | Algorithm | | |:-------------------------------------------------------------------------------------------------------------|:-----------------| -| [BLAKE](https://web.archive.org/web/20190915215948/https://131002.net/blake) | ✔️ | | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ | diff --git a/core/crypto/blake/blake.odin b/core/crypto/blake/blake.odin deleted file mode 100644 index 3685109e4..000000000 --- a/core/crypto/blake/blake.odin +++ /dev/null @@ -1,726 +0,0 @@ -package blake - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the BLAKE hashing algorithm, as defined in -*/ - -import "core:os" -import "core:io" - -/* - High level API -*/ - -DIGEST_SIZE_224 :: 28 -DIGEST_SIZE_256 :: 32 -DIGEST_SIZE_384 :: 48 -DIGEST_SIZE_512 :: 64 - -// hash_string_224 will hash the given input and return the -// computed hash -hash_string_224 :: proc "contextless" (data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224(transmute([]byte)(data)) -} - -// hash_bytes_224 will hash the given input and return the -// computed hash -hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: Blake256_Context - ctx.is224 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_224 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_224 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: Blake256_Context - ctx.is224 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_224 will read the stream in chunks and compute a -// hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: Blake256_Context - ctx.is224 = true - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_224 will read the file provided by the given handle -// and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false -} - -hash_224 :: proc { - hash_stream_224, - hash_file_224, - hash_bytes_224, - hash_string_224, - hash_bytes_to_buffer_224, - hash_string_to_buffer_224, -} - -// hash_string_256 will hash the given input and return the -// computed hash -hash_string_256 :: proc "contextless" (data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) -} - -// hash_bytes_256 will hash the given input and return the -// computed hash -hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Blake256_Context - ctx.is224 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Blake256_Context - ctx.is224 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_256 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Blake256_Context - ctx.is224 = false - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256 will read the file provided by the given handle -// and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, -} - -// hash_string_384 will hash the given input and return the -// computed hash -hash_string_384 :: proc "contextless" (data: string) -> [DIGEST_SIZE_384]byte { - return hash_bytes_384(transmute([]byte)(data)) -} - -// hash_bytes_384 will hash the given input and return the -// computed hash -hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte { - hash: [DIGEST_SIZE_384]byte - ctx: Blake512_Context - ctx.is384 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_384 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_384 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: Blake512_Context - ctx.is384 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_384 will read the stream in chunks and compute a -// hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { - hash: [DIGEST_SIZE_384]byte - ctx: Blake512_Context - ctx.is384 = true - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_384 will read the file provided by the given handle -// and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { - if !load_at_once { - return hash_stream_384(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_384(buf[:]), ok - } - } - return [DIGEST_SIZE_384]byte{}, false -} - -hash_384 :: proc { - hash_stream_384, - hash_file_384, - hash_bytes_384, - hash_string_384, - hash_bytes_to_buffer_384, - hash_string_to_buffer_384, -} - -// hash_string_512 will hash the given input and return the -// computed hash -hash_string_512 :: proc "contextless" (data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) -} - -// hash_bytes_512 will hash the given input and return the -// computed hash -hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: Blake512_Context - ctx.is384 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_512 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_512 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: Blake512_Context - ctx.is384 = false - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_512 will read the stream in chunks and compute a -// hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: Blake512_Context - ctx.is384 = false - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_512 will read the file provided by the given handle -// and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false -} - -hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, -} - -/* - Low level API -*/ - -init :: proc "contextless" (ctx: ^$T) { - when T == Blake256_Context { - if ctx.is224 { - ctx.h[0] = 0xc1059ed8 - ctx.h[1] = 0x367cd507 - ctx.h[2] = 0x3070dd17 - ctx.h[3] = 0xf70e5939 - ctx.h[4] = 0xffc00b31 - ctx.h[5] = 0x68581511 - ctx.h[6] = 0x64f98fa7 - ctx.h[7] = 0xbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667 - ctx.h[1] = 0xbb67ae85 - ctx.h[2] = 0x3c6ef372 - ctx.h[3] = 0xa54ff53a - ctx.h[4] = 0x510e527f - ctx.h[5] = 0x9b05688c - ctx.h[6] = 0x1f83d9ab - ctx.h[7] = 0x5be0cd19 - } - } else when T == Blake512_Context { - if ctx.is384 { - ctx.h[0] = 0xcbbb9d5dc1059ed8 - ctx.h[1] = 0x629a292a367cd507 - ctx.h[2] = 0x9159015a3070dd17 - ctx.h[3] = 0x152fecd8f70e5939 - ctx.h[4] = 0x67332667ffc00b31 - ctx.h[5] = 0x8eb44a8768581511 - ctx.h[6] = 0xdb0c2e0d64f98fa7 - ctx.h[7] = 0x47b5481dbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667f3bcc908 - ctx.h[1] = 0xbb67ae8584caa73b - ctx.h[2] = 0x3c6ef372fe94f82b - ctx.h[3] = 0xa54ff53a5f1d36f1 - ctx.h[4] = 0x510e527fade682d1 - ctx.h[5] = 0x9b05688c2b3e6c1f - ctx.h[6] = 0x1f83d9abfb41bd6b - ctx.h[7] = 0x5be0cd19137e2179 - } - } -} - -update :: proc "contextless" (ctx: ^$T, data: []byte) { - data := data - when T == Blake256_Context { - if ctx.nx > 0 { - n := copy(ctx.x[ctx.nx:], data) - ctx.nx += n - if ctx.nx == BLOCKSIZE_256 { - block256(ctx, ctx.x[:]) - ctx.nx = 0 - } - data = data[n:] - } - if len(data) >= BLOCKSIZE_256 { - n := len(data) &~ (BLOCKSIZE_256 - 1) - block256(ctx, data[:n]) - data = data[n:] - } - if len(data) > 0 { - ctx.nx = copy(ctx.x[:], data) - } - } else when T == Blake512_Context { - if ctx.nx > 0 { - n := copy(ctx.x[ctx.nx:], data) - ctx.nx += n - if ctx.nx == BLOCKSIZE_512 { - block512(ctx, ctx.x[:]) - ctx.nx = 0 - } - data = data[n:] - } - if len(data) >= BLOCKSIZE_512 { - n := len(data) &~ (BLOCKSIZE_512 - 1) - block512(ctx, data[:n]) - data = data[n:] - } - if len(data) > 0 { - ctx.nx = copy(ctx.x[:], data) - } - } -} - -final :: proc "contextless" (ctx: ^$T, hash: []byte) { - when T == Blake256_Context { - tmp: [65]byte - } else when T == Blake512_Context { - tmp: [129]byte - } - nx := u64(ctx.nx) - tmp[0] = 0x80 - length := (ctx.t + nx) << 3 - - when T == Blake256_Context { - if nx == 55 { - if ctx.is224 { - write_additional(ctx, {0x80}) - } else { - write_additional(ctx, {0x81}) - } - } else { - if nx < 55 { - if nx == 0 { - ctx.nullt = true - } - write_additional(ctx, tmp[0 : 55 - nx]) - } else { - write_additional(ctx, tmp[0 : 64 - nx]) - write_additional(ctx, tmp[1:56]) - ctx.nullt = true - } - if ctx.is224 { - write_additional(ctx, {0x00}) - } else { - write_additional(ctx, {0x01}) - } - } - - for i : uint = 0; i < 8; i += 1 { - tmp[i] = byte(length >> (56 - 8 * i)) - } - write_additional(ctx, tmp[0:8]) - - h := ctx.h[:] - if ctx.is224 { - h = h[0:7] - } - for s, i in h { - hash[i * 4] = byte(s >> 24) - hash[i * 4 + 1] = byte(s >> 16) - hash[i * 4 + 2] = byte(s >> 8) - hash[i * 4 + 3] = byte(s) - } - } else when T == Blake512_Context { - if nx == 111 { - if ctx.is384 { - write_additional(ctx, {0x80}) - } else { - write_additional(ctx, {0x81}) - } - } else { - if nx < 111 { - if nx == 0 { - ctx.nullt = true - } - write_additional(ctx, tmp[0 : 111 - nx]) - } else { - write_additional(ctx, tmp[0 : 128 - nx]) - write_additional(ctx, tmp[1:112]) - ctx.nullt = true - } - if ctx.is384 { - write_additional(ctx, {0x00}) - } else { - write_additional(ctx, {0x01}) - } - } - - for i : uint = 0; i < 16; i += 1 { - tmp[i] = byte(length >> (120 - 8 * i)) - } - write_additional(ctx, tmp[0:16]) - - h := ctx.h[:] - if ctx.is384 { - h = h[0:6] - } - for s, i in h { - hash[i * 8] = byte(s >> 56) - hash[i * 8 + 1] = byte(s >> 48) - hash[i * 8 + 2] = byte(s >> 40) - hash[i * 8 + 3] = byte(s >> 32) - hash[i * 8 + 4] = byte(s >> 24) - hash[i * 8 + 5] = byte(s >> 16) - hash[i * 8 + 6] = byte(s >> 8) - hash[i * 8 + 7] = byte(s) - } - } -} - -SIZE_224 :: 28 -SIZE_256 :: 32 -SIZE_384 :: 48 -SIZE_512 :: 64 -BLOCKSIZE_256 :: 64 -BLOCKSIZE_512 :: 128 - -Blake256_Context :: struct { - h: [8]u32, - s: [4]u32, - t: u64, - x: [64]byte, - nx: int, - is224: bool, - nullt: bool, -} - -Blake512_Context :: struct { - h: [8]u64, - s: [4]u64, - t: u64, - x: [128]byte, - nx: int, - is384: bool, - nullt: bool, -} - -SIGMA := [?]int { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, - 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, - 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, - 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, - 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, - 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, - 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, - 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, - 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, -} - -U256 := [16]u32 { - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, -} - -U512 := [16]u64 { - 0x243f6a8885a308d3, 0x13198a2e03707344, 0xa4093822299f31d0, 0x082efa98ec4e6c89, - 0x452821e638d01377, 0xbe5466cf34e90c6c, 0xc0ac29b7c97c50dd, 0x3f84d5b5b5470917, - 0x9216d5d98979fb1b, 0xd1310ba698dfb5ac, 0x2ffd72dbd01adfb7, 0xb8e1afed6a267e96, - 0xba7c9045f12c7f99, 0x24a19947b3916cf7, 0x0801f2e2858efc16, 0x636920d871574e69, -} - -G256 :: #force_inline proc "contextless" (a, b, c, d: u32, m: [16]u32, i, j: int) -> (u32, u32, u32, u32) { - a, b, c, d := a, b, c, d - a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j + 1)]] - a += b - d ~= a - d = d << (32 - 16) | d >> 16 - c += d - b ~= c - b = b << (32 - 12) | b >> 12 - a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j)]] - a += b - d ~= a - d = d << (32 - 8) | d >> 8 - c += d - b ~= c - b = b << (32 - 7) | b >> 7 - return a, b, c, d -} - -G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int) -> (u64, u64, u64, u64) { - a, b, c, d := a, b, c, d - a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j + 1)]] - a += b - d ~= a - d = d << (64 - 32) | d >> 32 - c += d - b ~= c - b = b << (64 - 25) | b >> 25 - a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j)]] - a += b - d ~= a - d = d << (64 - 16) | d >> 16 - c += d - b ~= c - b = b << (64 - 11) | b >> 11 - return a, b, c, d -} - -block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) #no_bounds_check { - i, j: int = ---, --- - v, m: [16]u32 = ---, --- - p := p - for len(p) >= BLOCKSIZE_256 { - v[0] = ctx.h[0] - v[1] = ctx.h[1] - v[2] = ctx.h[2] - v[3] = ctx.h[3] - v[4] = ctx.h[4] - v[5] = ctx.h[5] - v[6] = ctx.h[6] - v[7] = ctx.h[7] - v[8] = ctx.s[0] ~ U256[0] - v[9] = ctx.s[1] ~ U256[1] - v[10] = ctx.s[2] ~ U256[2] - v[11] = ctx.s[3] ~ U256[3] - v[12] = U256[4] - v[13] = U256[5] - v[14] = U256[6] - v[15] = U256[7] - - ctx.t += 512 - if !ctx.nullt { - v[12] ~= u32(ctx.t) - v[13] ~= u32(ctx.t) - v[14] ~= u32(ctx.t >> 32) - v[15] ~= u32(ctx.t >> 32) - } - - for i, j = 0, 0; i < 16; i, j = i+1, j+4 { - m[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3]) - } - - for i = 0; i < 14; i += 1 { - v[0], v[4], v[8], v[12] = G256(v[0], v[4], v[8], v[12], m, i, 0) - v[1], v[5], v[9], v[13] = G256(v[1], v[5], v[9], v[13], m, i, 1) - v[2], v[6], v[10], v[14] = G256(v[2], v[6], v[10], v[14], m, i, 2) - v[3], v[7], v[11], v[15] = G256(v[3], v[7], v[11], v[15], m, i, 3) - v[0], v[5], v[10], v[15] = G256(v[0], v[5], v[10], v[15], m, i, 4) - v[1], v[6], v[11], v[12] = G256(v[1], v[6], v[11], v[12], m, i, 5) - v[2], v[7], v[8], v[13] = G256(v[2], v[7], v[8], v[13], m, i, 6) - v[3], v[4], v[9], v[14] = G256(v[3], v[4], v[9], v[14], m, i, 7) - } - - for i = 0; i < 8; i += 1 { - ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8] - } - p = p[BLOCKSIZE_256:] - } -} - -block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check { - i, j: int = ---, --- - v, m: [16]u64 = ---, --- - p := p - for len(p) >= BLOCKSIZE_512 { - v[0] = ctx.h[0] - v[1] = ctx.h[1] - v[2] = ctx.h[2] - v[3] = ctx.h[3] - v[4] = ctx.h[4] - v[5] = ctx.h[5] - v[6] = ctx.h[6] - v[7] = ctx.h[7] - v[8] = ctx.s[0] ~ U512[0] - v[9] = ctx.s[1] ~ U512[1] - v[10] = ctx.s[2] ~ U512[2] - v[11] = ctx.s[3] ~ U512[3] - v[12] = U512[4] - v[13] = U512[5] - v[14] = U512[6] - v[15] = U512[7] - - ctx.t += 1024 - if !ctx.nullt { - v[12] ~= ctx.t - v[13] ~= ctx.t - v[14] ~= 0 - v[15] ~= 0 - } - - for i, j = 0, 0; i < 16; i, j = i + 1, j + 8 { - m[i] = u64(p[j]) << 56 | u64(p[j + 1]) << 48 | u64(p[j + 2]) << 40 | u64(p[j + 3]) << 32 | - u64(p[j + 4]) << 24 | u64(p[j + 5]) << 16 | u64(p[j + 6]) << 8 | u64(p[j + 7]) - } - for i = 0; i < 16; i += 1 { - v[0], v[4], v[8], v[12] = G512(v[0], v[4], v[8], v[12], m, i, 0) - v[1], v[5], v[9], v[13] = G512(v[1], v[5], v[9], v[13], m, i, 1) - v[2], v[6], v[10], v[14] = G512(v[2], v[6], v[10], v[14], m, i, 2) - v[3], v[7], v[11], v[15] = G512(v[3], v[7], v[11], v[15], m, i, 3) - v[0], v[5], v[10], v[15] = G512(v[0], v[5], v[10], v[15], m, i, 4) - v[1], v[6], v[11], v[12] = G512(v[1], v[6], v[11], v[12], m, i, 5) - v[2], v[7], v[8], v[13] = G512(v[2], v[7], v[8], v[13], m, i, 6) - v[3], v[4], v[9], v[14] = G512(v[3], v[4], v[9], v[14], m, i, 7) - } - - for i = 0; i < 8; i += 1 { - ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8] - } - p = p[BLOCKSIZE_512:] - } -} - -write_additional :: proc "contextless" (ctx: ^$T, data: []byte) { - ctx.t -= u64(len(data)) << 3 - update(ctx, data) -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index c6b727e42..96133e0e6 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -23,7 +23,6 @@ import list "core:container/intrusive/list" import topological_sort "core:container/topological_sort" import crypto "core:crypto" -import blake "core:crypto/blake" import blake2b "core:crypto/blake2b" import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" @@ -150,7 +149,6 @@ _ :: lru _ :: list _ :: topological_sort _ :: crypto -_ :: blake _ :: blake2b _ :: blake2s _ :: chacha20 diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index ad1c5738d..d8b2c27e7 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -26,7 +26,6 @@ import "core:crypto/keccak" import "core:crypto/shake" import "core:crypto/whirlpool" import "core:crypto/ripemd" -import "core:crypto/blake" import "core:crypto/blake2b" import "core:crypto/blake2s" import "core:crypto/tiger" @@ -86,10 +85,6 @@ main :: proc() { test_gost(&t) test_streebog_256(&t) test_streebog_512(&t) - test_blake_224(&t) - test_blake_256(&t) - test_blake_384(&t) - test_blake_512(&t) test_blake2b(&t) test_blake2s(&t) test_ripemd_128(&t) @@ -571,62 +566,6 @@ test_streebog_512 :: proc(t: ^testing.T) { } } -@(test) -test_blake_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, - TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, - TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_blake_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, - TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, - TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_blake_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, - TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, - TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_blake_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, - TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, - TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_blake2b :: proc(t: ^testing.T) { test_vectors := [?]TestHash { From 8438d66e6b8286559af410da8f498efae9341bca Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:31:58 +0900 Subject: [PATCH 090/160] core/crypto/gost: Remove, exotic --- core/crypto/README.md | 1 - core/crypto/gost/gost.odin | 382 ---------------------- examples/all/all_main.odin | 2 - examples/all/all_vendor.odin | 2 - tests/core/crypto/test_core_crypto.odin | 22 -- tests/vendor/botan/test_vendor_botan.odin | 22 -- vendor/botan/README.md | 1 - vendor/botan/bindings/botan.odin | 1 - vendor/botan/gost/gost.odin | 121 ------- 9 files changed, 554 deletions(-) delete mode 100644 core/crypto/gost/gost.odin delete mode 100644 vendor/botan/gost/gost.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index 3a8f81842..a5013dc0f 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -10,7 +10,6 @@ Please see the chart below for the options. |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | -| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ | | [Grøstl](http://www.groestl.info/Groestl.zip) | ✔️ | | [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ | | [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ | diff --git a/core/crypto/gost/gost.odin b/core/crypto/gost/gost.odin deleted file mode 100644 index 5aca8ce95..000000000 --- a/core/crypto/gost/gost.odin +++ /dev/null @@ -1,382 +0,0 @@ -package gost - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the GOST hashing algorithm, as defined in RFC 5831 -*/ - -import "core:mem" -import "core:os" -import "core:io" - -/* - High level API -*/ - -DIGEST_SIZE :: 32 - -// hash_string will hash the given input and return the -// computed hash -hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) -} - -// hash_bytes will hash the given input and return the -// computed hash -hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: Gost_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: Gost_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream will read the stream in chunks and compute a -// hash from its contents -hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: Gost_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file will read the file provided by the given handle -// and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false -} - -hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, -} - -/* - Low level API -*/ - -init :: proc "contextless" (ctx: ^Gost_Context) { - sbox: [8][16]u32 = { - { 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15 }, - { 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8 }, - { 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13 }, - { 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3 }, - { 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5 }, - { 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3 }, - { 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11 }, - { 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12 }, - } - - i := 0 - for a := 0; a < 16; a += 1 { - ax := sbox[1][a] << 15 - bx := sbox[3][a] << 23 - cx := sbox[5][a] - cx = (cx >> 1) | (cx << 31) - dx := sbox[7][a] << 7 - for b := 0; b < 16; b, i = b + 1, i + 1 { - SBOX_1[i] = ax | (sbox[0][b] << 11) - SBOX_2[i] = bx | (sbox[2][b] << 19) - SBOX_3[i] = cx | (sbox[4][b] << 27) - SBOX_4[i] = dx | (sbox[6][b] << 3) - } - } -} - -update :: proc(ctx: ^Gost_Context, data: []byte) { - length := byte(len(data)) - j: byte - - i := ctx.partial_bytes - for i < 32 && j < length { - ctx.partial[i] = data[j] - i, j = i + 1, j + 1 - } - - if i < 32 { - ctx.partial_bytes = i - return - } - bytes(ctx, ctx.partial[:], 256) - - for (j + 32) < length { - bytes(ctx, data[j:], 256) - j += 32 - } - - i = 0 - for j < length { - ctx.partial[i] = data[j] - i, j = i + 1, j + 1 - } - ctx.partial_bytes = i -} - -final :: proc(ctx: ^Gost_Context, hash: []byte) { - if ctx.partial_bytes > 0 { - mem.set(&ctx.partial[ctx.partial_bytes], 0, 32 - int(ctx.partial_bytes)) - bytes(ctx, ctx.partial[:], u32(ctx.partial_bytes) << 3) - } - - compress(ctx.hash[:], ctx.len[:]) - compress(ctx.hash[:], ctx.sum[:]) - - for i, j := 0, 0; i < 8; i, j = i + 1, j + 4 { - hash[j] = byte(ctx.hash[i]) - hash[j + 1] = byte(ctx.hash[i] >> 8) - hash[j + 2] = byte(ctx.hash[i] >> 16) - hash[j + 3] = byte(ctx.hash[i] >> 24) - } -} - -/* - GOST implementation -*/ - -Gost_Context :: struct { - sum: [8]u32, - hash: [8]u32, - len: [8]u32, - partial: [32]byte, - partial_bytes: byte, -} - -SBOX_1: [256]u32 -SBOX_2: [256]u32 -SBOX_3: [256]u32 -SBOX_4: [256]u32 - -ENCRYPT_ROUND :: #force_inline proc "contextless" (l, r, t, k1, k2: u32) -> (u32, u32, u32) { - l, r, t := l, r, t - t = (k1) + r - l ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24] - t = (k2) + l - r ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24] - return l, r, t -} - -ENCRYPT :: #force_inline proc "contextless" (a, b, c: u32, key: []u32) -> (l, r, t: u32) { - l, r, t = ENCRYPT_ROUND(a, b, c, key[0], key[1]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[7], key[6]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[5], key[4]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[3], key[2]) - l, r, t = ENCRYPT_ROUND(l, r, t, key[1], key[0]) - t = r - r = l - l = t - return -} - -bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) { - a, c: u32 - m: [8]u32 - - for i, j := 0, 0; i < 8; i += 1 { - a = u32(buf[j]) | u32(buf[j + 1]) << 8 | u32(buf[j + 2]) << 16 | u32(buf[j + 3]) << 24 - j += 4 - m[i] = a - c = a + c + ctx.sum[i] - ctx.sum[i] = c - c = c < a ? 1 : 0 - } - - compress(ctx.hash[:], m[:]) - ctx.len[0] += bits - if ctx.len[0] < bits { - ctx.len[1] += 1 - } -} - -compress :: proc(h, m: []u32) { - key, u, v, w, s: [8]u32 - - copy(u[:], h) - copy(v[:], m) - - for i := 0; i < 8; i += 2 { - w[0] = u[0] ~ v[0] - w[1] = u[1] ~ v[1] - w[2] = u[2] ~ v[2] - w[3] = u[3] ~ v[3] - w[4] = u[4] ~ v[4] - w[5] = u[5] ~ v[5] - w[6] = u[6] ~ v[6] - w[7] = u[7] ~ v[7] - - key[0] = (w[0] & 0x000000ff) | (w[2] & 0x000000ff) << 8 | (w[4] & 0x000000ff) << 16 | (w[6] & 0x000000ff) << 24 - key[1] = (w[0] & 0x0000ff00) >> 8 | (w[2] & 0x0000ff00) | (w[4] & 0x0000ff00) << 8 | (w[6] & 0x0000ff00) << 16 - key[2] = (w[0] & 0x00ff0000) >> 16 | (w[2] & 0x00ff0000) >> 8 | (w[4] & 0x00ff0000) | (w[6] & 0x00ff0000) << 8 - key[3] = (w[0] & 0xff000000) >> 24 | (w[2] & 0xff000000) >> 16 | (w[4] & 0xff000000) >> 8 | (w[6] & 0xff000000) - key[4] = (w[1] & 0x000000ff) | (w[3] & 0x000000ff) << 8 | (w[5] & 0x000000ff) << 16 | (w[7] & 0x000000ff) << 24 - key[5] = (w[1] & 0x0000ff00) >> 8 | (w[3] & 0x0000ff00) | (w[5] & 0x0000ff00) << 8 | (w[7] & 0x0000ff00) << 16 - key[6] = (w[1] & 0x00ff0000) >> 16 | (w[3] & 0x00ff0000) >> 8 | (w[5] & 0x00ff0000) | (w[7] & 0x00ff0000) << 8 - key[7] = (w[1] & 0xff000000) >> 24 | (w[3] & 0xff000000) >> 16 | (w[5] & 0xff000000) >> 8 | (w[7] & 0xff000000) - - r := h[i] - l := h[i + 1] - t: u32 - l, r, t = ENCRYPT(l, r, 0, key[:]) - - s[i] = r - s[i + 1] = l - - if i == 6 { - break - } - - l = u[0] ~ u[2] - r = u[1] ~ u[3] - u[0] = u[2] - u[1] = u[3] - u[2] = u[4] - u[3] = u[5] - u[4] = u[6] - u[5] = u[7] - u[6] = l - u[7] = r - - if i == 2 { - u[0] ~= 0xff00ff00 - u[1] ~= 0xff00ff00 - u[2] ~= 0x00ff00ff - u[3] ~= 0x00ff00ff - u[4] ~= 0x00ffff00 - u[5] ~= 0xff0000ff - u[6] ~= 0x000000ff - u[7] ~= 0xff00ffff - } - - l = v[0] - r = v[2] - v[0] = v[4] - v[2] = v[6] - v[4] = l ~ r - v[6] = v[0] ~ r - l = v[1] - r = v[3] - v[1] = v[5] - v[3] = v[7] - v[5] = l ~ r - v[7] = v[1] ~ r - } - - u[0] = m[0] ~ s[6] - u[1] = m[1] ~ s[7] - u[2] = m[2] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff) ~ - (s[1] & 0xffff) ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[6] ~ (s[6] << 16) ~ - (s[7] & 0xffff0000) ~ (s[7] >> 16) - u[3] = m[3] ~ (s[0] & 0xffff) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~ - (s[1] << 16) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~ - (s[3] << 16) ~ s[6] ~ (s[6] << 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~ - (s[7] << 16) ~ (s[7] >> 16) - u[4] = m[4] ~ - (s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[0] >> 16) ~ - (s[1] & 0xffff0000) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~ - (s[3] << 16) ~ (s[3] >> 16) ~ (s[4] << 16) ~ (s[6] << 16) ~ - (s[6] >> 16) ~(s[7] & 0xffff) ~ (s[7] << 16) ~ (s[7] >> 16) - u[5] = m[5] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff0000) ~ - (s[1] & 0xffff) ~ s[2] ~ (s[2] >> 16) ~ (s[3] << 16) ~ (s[3] >> 16) ~ - (s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[6] << 16) ~ - (s[6] >> 16) ~ (s[7] & 0xffff0000) ~ (s[7] << 16) ~ (s[7] >> 16) - u[6] = m[6] ~ s[0] ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[3] ~ (s[3] >> 16) ~ - (s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[5] >> 16) ~ s[6] ~ - (s[6] << 16) ~ (s[6] >> 16) ~ (s[7] << 16) - u[7] = m[7] ~ (s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~ - (s[1] << 16) ~ (s[2] >> 16) ~ (s[3] << 16) ~ s[4] ~ (s[4] >> 16) ~ - (s[5] << 16) ~ (s[5] >> 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~ - (s[7] << 16) ~ (s[7] >> 16) - - v[0] = h[0] ~ (u[1] << 16) ~ (u[0] >> 16) - v[1] = h[1] ~ (u[2] << 16) ~ (u[1] >> 16) - v[2] = h[2] ~ (u[3] << 16) ~ (u[2] >> 16) - v[3] = h[3] ~ (u[4] << 16) ~ (u[3] >> 16) - v[4] = h[4] ~ (u[5] << 16) ~ (u[4] >> 16) - v[5] = h[5] ~ (u[6] << 16) ~ (u[5] >> 16) - v[6] = h[6] ~ (u[7] << 16) ~ (u[6] >> 16) - v[7] = h[7] ~ (u[0] & 0xffff0000) ~ (u[0] << 16) ~ (u[7] >> 16) ~ (u[1] & 0xffff0000) ~ (u[1] << 16) ~ (u[6] << 16) ~ (u[7] & 0xffff0000) - - h[0] = (v[0] & 0xffff0000) ~ (v[0] << 16) ~ (v[0] >> 16) ~ (v[1] >> 16) ~ - (v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ (v[4] << 16) ~ - (v[5] >> 16) ~ v[5] ~ (v[6] >> 16) ~ (v[7] << 16) ~ (v[7] >> 16) ~ - (v[7] & 0xffff) - h[1] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~ (v[1] & 0xffff) ~ - v[2] ~ (v[2] >> 16) ~ (v[3] << 16) ~ (v[4] >> 16) ~ (v[5] << 16) ~ - (v[6] << 16) ~ v[6] ~ (v[7] & 0xffff0000) ~ (v[7] >> 16) - h[2] = (v[0] & 0xffff) ~ (v[0] << 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~ - (v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ - (v[5] >> 16) ~ v[6] ~ (v[6] >> 16) ~ (v[7] & 0xffff) ~ (v[7] << 16) ~ - (v[7] >> 16) - h[3] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~ - (v[1] & 0xffff0000) ~ (v[1] >> 16) ~ (v[2] << 16) ~ (v[2] >> 16) ~ v[2] ~ - (v[3] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~ - (v[7] & 0xffff) ~ (v[7] >> 16) - h[4] = (v[0] >> 16) ~ (v[1] << 16) ~ v[1] ~ (v[2] >> 16) ~ v[2] ~ - (v[3] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ (v[5] >> 16) ~ - v[5] ~ (v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16) - h[5] = (v[0] << 16) ~ (v[0] & 0xffff0000) ~ (v[1] << 16) ~ (v[1] >> 16) ~ - (v[1] & 0xffff0000) ~ (v[2] << 16) ~ v[2] ~ (v[3] >> 16) ~ v[3] ~ - (v[4] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~ - (v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ (v[7] >> 16) ~ (v[7] & 0xffff0000) - h[6] = v[0] ~ v[2] ~ (v[2] >> 16) ~ v[3] ~ (v[3] << 16) ~ v[4] ~ - (v[4] >> 16) ~ (v[5] << 16) ~ (v[5] >> 16) ~ v[5] ~ (v[6] << 16) ~ - (v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ v[7] - h[7] = v[0] ~ (v[0] >> 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~ (v[2] << 16) ~ - (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ v[4] ~ (v[5] >> 16) ~ v[5] ~ - (v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16) ~ v[7] -} \ No newline at end of file diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 96133e0e6..3f5ea59cf 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -27,7 +27,6 @@ import blake2b "core:crypto/blake2b" import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" import chacha20poly1305 "core:crypto/chacha20poly1305" -import gost "core:crypto/gost" import groestl "core:crypto/groestl" import haval "core:crypto/haval" import jh "core:crypto/jh" @@ -153,7 +152,6 @@ _ :: blake2b _ :: blake2s _ :: chacha20 _ :: chacha20poly1305 -_ :: gost _ :: groestl _ :: haval _ :: jh diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 6864a7be2..0a13d74bd 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -2,7 +2,6 @@ package all import botan_bindings "vendor:botan/bindings" import botan_blake2b "vendor:botan/blake2b" -import gost "vendor:botan/gost" import keccak "vendor:botan/keccak" import md4 "vendor:botan/md4" import md5 "vendor:botan/md5" @@ -48,7 +47,6 @@ import fontstash "vendor:fontstash" _ :: botan_bindings _ :: botan_blake2b -_ :: gost _ :: keccak _ :: md4 _ :: md5 diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index d8b2c27e7..f8a1e4d44 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -30,7 +30,6 @@ import "core:crypto/blake2b" import "core:crypto/blake2s" import "core:crypto/tiger" import "core:crypto/tiger2" -import "core:crypto/gost" import "core:crypto/streebog" import "core:crypto/sm3" import "core:crypto/jh" @@ -82,7 +81,6 @@ main :: proc() { test_keccak_384(&t) test_keccak_512(&t) test_whirlpool(&t) - test_gost(&t) test_streebog_256(&t) test_streebog_512(&t) test_blake2b(&t) @@ -518,26 +516,6 @@ test_whirlpool :: proc(t: ^testing.T) { } } -@(test) -test_gost :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, - TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, - TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, - TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, - TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, - TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, - TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, - } - for v, _ in test_vectors { - computed := gost.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_streebog_256 :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 51043d813..eecfdd692 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -28,7 +28,6 @@ import "vendor:botan/whirlpool" import "vendor:botan/ripemd" import "vendor:botan/blake2b" import "vendor:botan/tiger" -import "vendor:botan/gost" import "vendor:botan/streebog" import "vendor:botan/sm3" import "vendor:botan/skein512" @@ -74,7 +73,6 @@ main :: proc() { // test_shake_256(&t) test_keccak_512(&t) test_whirlpool(&t) - test_gost(&t) test_streebog_256(&t) test_streebog_512(&t) test_blake2b(&t) @@ -401,26 +399,6 @@ test_whirlpool :: proc(t: ^testing.T) { } } -@(test) -test_gost :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, - TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, - TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, - TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, - TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, - TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, - TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, - } - for v, _ in test_vectors { - computed := gost.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_streebog_256 :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/vendor/botan/README.md b/vendor/botan/README.md index b7d4d01a1..539e2f820 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -9,7 +9,6 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | Algorithm | | |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | -| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | | [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 7c8b0997a..0a36dbdd9 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -82,7 +82,6 @@ HASH_MD5 :: "MD5" HASH_TIGER_128 :: "Tiger(16,3)" HASH_TIGER_160 :: "Tiger(20,3)" HASH_TIGER_192 :: "Tiger(24,3)" -HASH_GOST :: "GOST-34.11" HASH_STREEBOG_256 :: "Streebog-256" HASH_STREEBOG_512 :: "Streebog-512" HASH_SM3 :: "SM3" diff --git a/vendor/botan/gost/gost.odin b/vendor/botan/gost/gost.odin deleted file mode 100644 index 5b3db31fe..000000000 --- a/vendor/botan/gost/gost.odin +++ /dev/null @@ -1,121 +0,0 @@ -package vendor_gost - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial implementation. - - Interface for the GOST hashing algorithm. - The hash will be computed via bindings to the Botan crypto library -*/ - -import "core:os" -import "core:io" - -import botan "../bindings" - -/* - High level API -*/ - -DIGEST_SIZE :: 32 - -// hash_string will hash the given input and return the -// computed hash -hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) -} - -// hash_bytes will hash the given input and return the -// computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_GOST, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_GOST, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream will read the stream in chunks and compute a -// hash from its contents -hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_GOST, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file will read the file provided by the given handle -// and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false -} - -hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, -} - -/* - Low level API -*/ - -Gost_Context :: botan.hash_t - -init :: proc "contextless" (ctx: ^botan.hash_t) { - botan.hash_init(ctx, botan.HASH_GOST, 0) -} - -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { - botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) -} - -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { - botan.hash_final(ctx^, &hash[0]) - botan.hash_destroy(ctx^) -} From 65204f13a8179d060d8ae89391bcec5823fe9921 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:35:08 +0900 Subject: [PATCH 091/160] core/crypto/groestl: Remove, use SHA-3 --- core/crypto/README.md | 1 - core/crypto/groestl/groestl.odin | 653 ------------------------ examples/all/all_main.odin | 2 - tests/core/crypto/test_core_crypto.odin | 61 --- 4 files changed, 717 deletions(-) delete mode 100644 core/crypto/groestl/groestl.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index a5013dc0f..e5f9c533c 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -10,7 +10,6 @@ Please see the chart below for the options. |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | -| [Grøstl](http://www.groestl.info/Groestl.zip) | ✔️ | | [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ | | [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | diff --git a/core/crypto/groestl/groestl.odin b/core/crypto/groestl/groestl.odin deleted file mode 100644 index 61460808f..000000000 --- a/core/crypto/groestl/groestl.odin +++ /dev/null @@ -1,653 +0,0 @@ -package groestl - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the GROESTL hashing algorithm, as defined in -*/ - -import "core:os" -import "core:io" - -/* - High level API -*/ - -DIGEST_SIZE_224 :: 28 -DIGEST_SIZE_256 :: 32 -DIGEST_SIZE_384 :: 48 -DIGEST_SIZE_512 :: 64 - -// hash_string_224 will hash the given input and return the -// computed hash -hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224(transmute([]byte)(data)) -} - -// hash_bytes_224 will hash the given input and return the -// computed hash -hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: Groestl_Context - ctx.hashbitlen = 224 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_224 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_224 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: Groestl_Context - ctx.hashbitlen = 224 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_224 will read the stream in chunks and compute a -// hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: Groestl_Context - ctx.hashbitlen = 224 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_224 will read the file provided by the given handle -// and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false -} - -hash_224 :: proc { - hash_stream_224, - hash_file_224, - hash_bytes_224, - hash_string_224, - hash_bytes_to_buffer_224, - hash_string_to_buffer_224, -} - -// hash_string_256 will hash the given input and return the -// computed hash -hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) -} - -// hash_bytes_256 will hash the given input and return the -// computed hash -hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Groestl_Context - ctx.hashbitlen = 256 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Groestl_Context - ctx.hashbitlen = 256 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_256 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Groestl_Context - ctx.hashbitlen = 256 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256 will read the file provided by the given handle -// and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, -} - -// hash_string_384 will hash the given input and return the -// computed hash -hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { - return hash_bytes_384(transmute([]byte)(data)) -} - -// hash_bytes_384 will hash the given input and return the -// computed hash -hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { - hash: [DIGEST_SIZE_384]byte - ctx: Groestl_Context - ctx.hashbitlen = 384 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_384 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_384 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: Groestl_Context - ctx.hashbitlen = 384 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_384 will read the stream in chunks and compute a -// hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { - hash: [DIGEST_SIZE_384]byte - ctx: Groestl_Context - ctx.hashbitlen = 384 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_384 will read the file provided by the given handle -// and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { - if !load_at_once { - return hash_stream_384(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_384(buf[:]), ok - } - } - return [DIGEST_SIZE_384]byte{}, false -} - -hash_384 :: proc { - hash_stream_384, - hash_file_384, - hash_bytes_384, - hash_string_384, - hash_bytes_to_buffer_384, - hash_string_to_buffer_384, -} - -// hash_string_512 will hash the given input and return the -// computed hash -hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) -} - -// hash_bytes_512 will hash the given input and return the -// computed hash -hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: Groestl_Context - ctx.hashbitlen = 512 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_512 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_512 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: Groestl_Context - ctx.hashbitlen = 512 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_512 will read the stream in chunks and compute a -// hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: Groestl_Context - ctx.hashbitlen = 512 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_512 will read the file provided by the given handle -// and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false -} - -hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, -} - -/* - Low level API -*/ - -init :: proc(ctx: ^Groestl_Context) { - assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512") - if ctx.hashbitlen <= 256 { - ctx.rounds = 10 - ctx.columns = 8 - ctx.statesize = 64 - } else { - ctx.rounds = 14 - ctx.columns = 16 - ctx.statesize = 128 - } - for i := 8 - size_of(i32); i < 8; i += 1 { - ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i)))) - } -} - -update :: proc(ctx: ^Groestl_Context, data: []byte) { - databitlen := len(data) * 8 - msglen := databitlen / 8 - rem := databitlen % 8 - - i: int - assert(ctx.bits_in_last_byte == 0) - - if ctx.buf_ptr != 0 { - for i = 0; ctx.buf_ptr < ctx.statesize && i < msglen; i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 { - ctx.buffer[ctx.buf_ptr] = data[i] - } - - if ctx.buf_ptr < ctx.statesize { - if rem != 0 { - ctx.bits_in_last_byte = rem - ctx.buffer[ctx.buf_ptr] = data[i] - ctx.buf_ptr += 1 - } - return - } - - ctx.buf_ptr = 0 - transform(ctx, ctx.buffer[:], u32(ctx.statesize)) - } - - transform(ctx, data[i:], u32(msglen - i)) - i += ((msglen - i) / ctx.statesize) * ctx.statesize - for i < msglen { - ctx.buffer[ctx.buf_ptr] = data[i] - i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 - } - - if rem != 0 { - ctx.bits_in_last_byte = rem - ctx.buffer[ctx.buf_ptr] = data[i] - ctx.buf_ptr += 1 - } -} - -final :: proc(ctx: ^Groestl_Context, hash: []byte) { - hashbytelen := ctx.hashbitlen / 8 - - if ctx.bits_in_last_byte != 0 { - ctx.buffer[ctx.buf_ptr - 1] &= ((1 << uint(ctx.bits_in_last_byte)) - 1) << (8 - uint(ctx.bits_in_last_byte)) - ctx.buffer[ctx.buf_ptr - 1] ~= 0x1 << (7 - uint(ctx.bits_in_last_byte)) - } else { - ctx.buffer[ctx.buf_ptr] = 0x80 - ctx.buf_ptr += 1 - } - - if ctx.buf_ptr > ctx.statesize - 8 { - for ctx.buf_ptr < ctx.statesize { - ctx.buffer[ctx.buf_ptr] = 0 - ctx.buf_ptr += 1 - } - transform(ctx, ctx.buffer[:], u32(ctx.statesize)) - ctx.buf_ptr = 0 - } - - for ctx.buf_ptr < ctx.statesize - 8 { - ctx.buffer[ctx.buf_ptr] = 0 - ctx.buf_ptr += 1 - } - - ctx.block_counter += 1 - ctx.buf_ptr = ctx.statesize - - for ctx.buf_ptr > ctx.statesize - 8 { - ctx.buf_ptr -= 1 - ctx.buffer[ctx.buf_ptr] = byte(ctx.block_counter) - ctx.block_counter >>= 8 - } - - transform(ctx, ctx.buffer[:], u32(ctx.statesize)) - output_transformation(ctx) - - for i, j := ctx.statesize - hashbytelen , 0; i < ctx.statesize; i, j = i + 1, j + 1 { - hash[j] = ctx.chaining[i % 8][i / 8] - } -} - -/* - GROESTL implementation -*/ - -SBOX := [256]byte { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, -} - -SHIFT := [2][2][8]int { - {{0, 1, 2, 3, 4, 5, 6, 7}, {1, 3, 5, 7, 0, 2, 4, 6}}, - {{0, 1, 2, 3, 4, 5, 6, 11}, {1, 3, 5, 11, 0, 2, 4, 6}}, -} - -Groestl_Context :: struct { - chaining: [8][16]byte, - block_counter: u64, - hashbitlen: int, - buffer: [128]byte, - buf_ptr: int, - bits_in_last_byte: int, - columns: int, - rounds: int, - statesize: int, -} - -Groestl_Variant :: enum { - P512 = 0, - Q512 = 1, - P1024 = 2, - Q1024 = 3, -} - -MUL2 :: #force_inline proc "contextless"(b: byte) -> byte { - return (b >> 7) != 0 ? (b << 1) ~ 0x1b : (b << 1) -} - -MUL3 :: #force_inline proc "contextless"(b: byte) -> byte { - return MUL2(b) ~ b -} - -MUL4 :: #force_inline proc "contextless"(b: byte) -> byte { - return MUL2(MUL2(b)) -} - -MUL5 :: #force_inline proc "contextless"(b: byte) -> byte { - return MUL4(b) ~ b -} - -MUL6 :: #force_inline proc "contextless"(b: byte) -> byte { - return MUL4(b) ~ MUL2(b) -} - -MUL7 :: #force_inline proc "contextless"(b: byte) -> byte { - return MUL4(b) ~ MUL2(b) ~ b -} - -sub_bytes :: #force_inline proc (x: [][16]byte, columns: int) { - for i := 0; i < 8; i += 1 { - for j := 0; j < columns; j += 1 { - x[i][j] = SBOX[x[i][j]] - } - } -} - -shift_bytes :: #force_inline proc (x: [][16]byte, columns: int, v: Groestl_Variant) { - temp: [16]byte - R := &SHIFT[int(v) / 2][int(v) & 1] - - for i := 0; i < 8; i += 1 { - for j := 0; j < columns; j += 1 { - temp[j] = x[i][(j + R[i]) % columns] - } - for j := 0; j < columns; j += 1 { - x[i][j] = temp[j] - } - } -} - -mix_bytes :: #force_inline proc (x: [][16]byte, columns: int) { - temp: [8]byte - - for i := 0; i < columns; i += 1 { - for j := 0; j < 8; j += 1 { - temp[j] = MUL2(x[(j + 0) % 8][i]) ~ - MUL2(x[(j + 1) % 8][i]) ~ - MUL3(x[(j + 2) % 8][i]) ~ - MUL4(x[(j + 3) % 8][i]) ~ - MUL5(x[(j + 4) % 8][i]) ~ - MUL3(x[(j + 5) % 8][i]) ~ - MUL5(x[(j + 6) % 8][i]) ~ - MUL7(x[(j + 7) % 8][i]) - } - for j := 0; j < 8; j += 1 { - x[j][i] = temp[j] - } - } -} - -p :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) { - v := ctx.columns == 8 ? Groestl_Variant.P512 : Groestl_Variant.P1024 - for i := 0; i < ctx.rounds; i += 1 { - add_roundconstant(x, ctx.columns, byte(i), v) - sub_bytes(x, ctx.columns) - shift_bytes(x, ctx.columns, v) - mix_bytes(x, ctx.columns) - } -} - -q :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) { - v := ctx.columns == 8 ? Groestl_Variant.Q512 : Groestl_Variant.Q1024 - for i := 0; i < ctx.rounds; i += 1 { - add_roundconstant(x, ctx.columns, byte(i), v) - sub_bytes(x, ctx.columns) - shift_bytes(x, ctx.columns, v) - mix_bytes(x, ctx.columns) - } -} - -transform :: proc(ctx: ^Groestl_Context, input: []byte, msglen: u32) { - tmp1, tmp2: [8][16]byte - input, msglen := input, msglen - - for msglen >= u32(ctx.statesize) { - for i := 0; i < 8; i += 1 { - for j := 0; j < ctx.columns; j += 1 { - tmp1[i][j] = ctx.chaining[i][j] ~ input[j * 8 + i] - tmp2[i][j] = input[j * 8 + i] - } - } - - p(ctx, tmp1[:]) - q(ctx, tmp2[:]) - - for i := 0; i < 8; i += 1 { - for j := 0; j < ctx.columns; j += 1 { - ctx.chaining[i][j] ~= tmp1[i][j] ~ tmp2[i][j] - } - } - - ctx.block_counter += 1 - msglen -= u32(ctx.statesize) - input = input[ctx.statesize:] - } -} - -output_transformation :: proc(ctx: ^Groestl_Context) { - temp: [8][16]byte - - for i := 0; i < 8; i += 1 { - for j := 0; j < ctx.columns; j += 1 { - temp[i][j] = ctx.chaining[i][j] - } - } - - p(ctx, temp[:]) - - for i := 0; i < 8; i += 1 { - for j := 0; j < ctx.columns; j += 1 { - ctx.chaining[i][j] ~= temp[i][j] - } - } -} - -add_roundconstant :: proc(x: [][16]byte, columns: int, round: byte, v: Groestl_Variant) { - switch (i32(v) & 1) { - case 0: - for i := 0; i < columns; i += 1 { - x[0][i] ~= byte(i << 4) ~ round - } - case 1: - for i := 0; i < columns; i += 1 { - for j := 0; j < 7; j += 1 { - x[j][i] ~= 0xff - } - } - for i := 0; i < columns; i += 1 { - x[7][i] ~= byte(i << 4) ~ 0xff ~ round - } - } -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 3f5ea59cf..70ce5629c 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -27,7 +27,6 @@ import blake2b "core:crypto/blake2b" import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" import chacha20poly1305 "core:crypto/chacha20poly1305" -import groestl "core:crypto/groestl" import haval "core:crypto/haval" import jh "core:crypto/jh" import keccak "core:crypto/keccak" @@ -152,7 +151,6 @@ _ :: blake2b _ :: blake2s _ :: chacha20 _ :: chacha20poly1305 -_ :: groestl _ :: haval _ :: jh _ :: keccak diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index f8a1e4d44..9f88be1b5 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -33,7 +33,6 @@ import "core:crypto/tiger2" import "core:crypto/streebog" import "core:crypto/sm3" import "core:crypto/jh" -import "core:crypto/groestl" import "core:crypto/haval" import "core:crypto/siphash" import "core:os" @@ -100,10 +99,6 @@ main :: proc() { test_jh_256(&t) test_jh_384(&t) test_jh_512(&t) - test_groestl_224(&t) - test_groestl_256(&t) - test_groestl_384(&t) - test_groestl_512(&t) test_haval_128(&t) test_haval_160(&t) test_haval_192(&t) @@ -824,62 +819,6 @@ test_jh_512 :: proc(t: ^testing.T) { } } -@(test) -test_groestl_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, - TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, - TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_groestl_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, - TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, - TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_groestl_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, - TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, - TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_groestl_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, - TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, - TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_haval_128 :: proc(t: ^testing.T) { test_vectors_3 := [?]TestHash { From 2a6fb3a387132c4ca7e88ab0d84b805b3570262e Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:38:36 +0900 Subject: [PATCH 092/160] core/crypto/haval: Remove, badly broken --- core/crypto/README.md | 1 - core/crypto/haval/haval.odin | 1814 ----------------------- examples/all/all_main.odin | 2 - tests/core/crypto/test_core_crypto.odin | 171 --- 4 files changed, 1988 deletions(-) delete mode 100644 core/crypto/haval/haval.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index e5f9c533c..3b02be26a 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -10,7 +10,6 @@ Please see the chart below for the options. |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | -| [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ | | [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ | diff --git a/core/crypto/haval/haval.odin b/core/crypto/haval/haval.odin deleted file mode 100644 index b98facb33..000000000 --- a/core/crypto/haval/haval.odin +++ /dev/null @@ -1,1814 +0,0 @@ -package haval - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation for the HAVAL hashing algorithm as defined in -*/ - -import "core:mem" -import "core:os" -import "core:io" - -import "../util" - -/* - High level API -*/ - -DIGEST_SIZE_128 :: 16 -DIGEST_SIZE_160 :: 20 -DIGEST_SIZE_192 :: 24 -DIGEST_SIZE_224 :: 28 -DIGEST_SIZE_256 :: 32 - -// hash_string_128_3 will hash the given input and return the -// computed hash -hash_string_128_3 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128_3(transmute([]byte)(data)) -} - -// hash_bytes_128_3 will hash the given input and return the -// computed hash -hash_bytes_128_3 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_128_3 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_128_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_128_3 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_128_3 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_128_3 will read the stream in chunks and compute a -// hash from its contents -hash_stream_128_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 3 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_128_3 will read the file provided by the given handle -// and compute a hash -hash_file_128_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128_3(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128_3(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false -} - -hash_128_3 :: proc { - hash_stream_128_3, - hash_file_128_3, - hash_bytes_128_3, - hash_string_128_3, - hash_bytes_to_buffer_128_3, - hash_string_to_buffer_128_3, -} - -// hash_string_128_4 will hash the given input and return the -// computed hash -hash_string_128_4 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128_4(transmute([]byte)(data)) -} - -// hash_bytes_128_4 will hash the given input and return the -// computed hash -hash_bytes_128_4 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_128_4 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_128_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_128_4 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_128_4 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_128_4 will read the stream in chunks and compute a -// hash from its contents -hash_stream_128_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 4 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_128_4 will read the file provided by the given handle -// and compute a hash -hash_file_128_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128_4(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128_4(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false -} - -hash_128_4 :: proc { - hash_stream_128_4, - hash_file_128_4, - hash_bytes_128_4, - hash_string_128_4, - hash_bytes_to_buffer_128_4, - hash_string_to_buffer_128_4, -} - -// hash_string_128_5 will hash the given input and return the -// computed hash -hash_string_128_5 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128_5(transmute([]byte)(data)) -} - -// hash_bytes_128_5 will hash the given input and return the -// computed hash -hash_bytes_128_5 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_128_5 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_128_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_128_5 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_128_5 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_128_5 will read the stream in chunks and compute a -// hash from its contents -hash_stream_128_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: Haval_Context - ctx.hashbitlen = 128 - ctx.rounds = 5 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_128_5 will read the file provided by the given handle -// and compute a hash -hash_file_128_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128_5(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128_5(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false -} - -hash_128_5 :: proc { - hash_stream_128_5, - hash_file_128_5, - hash_bytes_128_5, - hash_string_128_5, - hash_bytes_to_buffer_128_5, - hash_string_to_buffer_128_5, -} - -// hash_string_160_3 will hash the given input and return the -// computed hash -hash_string_160_3 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160_3(transmute([]byte)(data)) -} - -// hash_bytes_160_3 will hash the given input and return the -// computed hash -hash_bytes_160_3 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_160_3 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160_3 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160_3 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_160_3 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 3 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_160_3 will read the file provided by the given handle -// and compute a hash -hash_file_160_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160_3(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160_3(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160_3 :: proc { - hash_stream_160_3, - hash_file_160_3, - hash_bytes_160_3, - hash_string_160_3, - hash_bytes_to_buffer_160_3, - hash_string_to_buffer_160_3, -} - -// hash_string_160_4 will hash the given input and return the -// computed hash -hash_string_160_4 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160_4(transmute([]byte)(data)) -} - -// hash_bytes_160_4 will hash the given input and return the -// computed hash -hash_bytes_160_4 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_160_4 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160_4 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160_4 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_160_4 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 4 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_160_4 will read the file provided by the given handle -// and compute a hash -hash_file_160_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160_4(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160_4(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160_4 :: proc { - hash_stream_160_4, - hash_file_160_4, - hash_bytes_160_4, - hash_string_160_4, - hash_bytes_to_buffer_160_4, - hash_string_to_buffer_160_4, -} - -// hash_string_160_5 will hash the given input and return the -// computed hash -hash_string_160_5 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160_5(transmute([]byte)(data)) -} - -// hash_bytes_160_5 will hash the given input and return the -// computed hash -hash_bytes_160_5 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_160_5 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160_5 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160_5 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_160_5 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: Haval_Context - ctx.hashbitlen = 160 - ctx.rounds = 5 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_160_5 will read the file provided by the given handle -// and compute a hash -hash_file_160_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160_5(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160_5(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160_5 :: proc { - hash_stream_160_5, - hash_file_160_5, - hash_bytes_160_5, - hash_string_160_5, - hash_bytes_to_buffer_160_5, - hash_string_to_buffer_160_5, -} - -// hash_string_192_3 will hash the given input and return the -// computed hash -hash_string_192_3 :: proc(data: string) -> [DIGEST_SIZE_192]byte { - return hash_bytes_192_3(transmute([]byte)(data)) -} - -// hash_bytes_192_3 will hash the given input and return the -// computed hash -hash_bytes_192_3 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { - hash: [DIGEST_SIZE_192]byte - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_192_3 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_192_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_192_3 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_192_3 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_192_3 will read the stream in chunks and compute a -// hash from its contents -hash_stream_192_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { - hash: [DIGEST_SIZE_192]byte - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 3 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_192_3 will read the file provided by the given handle -// and compute a hash -hash_file_192_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { - if !load_at_once { - return hash_stream_192_3(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_192_3(buf[:]), ok - } - } - return [DIGEST_SIZE_192]byte{}, false -} - -hash_192_3 :: proc { - hash_stream_192_3, - hash_file_192_3, - hash_bytes_192_3, - hash_string_192_3, - hash_bytes_to_buffer_192_3, - hash_string_to_buffer_192_3, -} - -// hash_string_192_4 will hash the given input and return the -// computed hash -hash_string_192_4 :: proc(data: string) -> [DIGEST_SIZE_192]byte { - return hash_bytes_192_4(transmute([]byte)(data)) -} - -// hash_bytes_192_4 will hash the given input and return the -// computed hash -hash_bytes_192_4 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { - hash: [DIGEST_SIZE_192]byte - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_192_4 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_192_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_192_4 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_192_4 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_192_4 will read the stream in chunks and compute a -// hash from its contents -hash_stream_192_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { - hash: [DIGEST_SIZE_192]byte - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 4 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_192_4 will read the file provided by the given handle -// and compute a hash -hash_file_192_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { - if !load_at_once { - return hash_stream_192_4(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_192_4(buf[:]), ok - } - } - return [DIGEST_SIZE_192]byte{}, false -} - -hash_192_4 :: proc { - hash_stream_192_4, - hash_file_192_4, - hash_bytes_192_4, - hash_string_192_4, - hash_bytes_to_buffer_192_4, - hash_string_to_buffer_192_4, -} - -// hash_string_192_5 will hash the given input and return the -// computed hash -hash_string_192_5 :: proc(data: string) -> [DIGEST_SIZE_192]byte { - return hash_bytes_192_5(transmute([]byte)(data)) -} - -// hash_bytes_2DIGEST_SIZE_192_5 will hash the given input and return the -// computed hash -hash_bytes_192_5 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { - hash: [DIGEST_SIZE_192]byte - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_192_5 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_192_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_192_5 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_192_5 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_192_5 will read the stream in chunks and compute a -// hash from its contents -hash_stream_192_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { - hash: [DIGEST_SIZE_192]byte - ctx: Haval_Context - ctx.hashbitlen = 192 - ctx.rounds = 5 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_192_5 will read the file provided by the given handle -// and compute a hash -hash_file_192_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { - if !load_at_once { - return hash_stream_192_5(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_192_5(buf[:]), ok - } - } - return [DIGEST_SIZE_192]byte{}, false -} - -hash_192_5 :: proc { - hash_stream_192_5, - hash_file_192_5, - hash_bytes_192_5, - hash_string_192_5, - hash_bytes_to_buffer_192_5, - hash_string_to_buffer_192_5, -} - -// hash_string_224_3 will hash the given input and return the -// computed hash -hash_string_224_3 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224_3(transmute([]byte)(data)) -} - -// hash_bytes_224_3 will hash the given input and return the -// computed hash -hash_bytes_224_3 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_224_3 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_224_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_224_3 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_224_3 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_224_3 will read the stream in chunks and compute a -// hash from its contents -hash_stream_224_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 3 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_224_3 will read the file provided by the given handle -// and compute a hash -hash_file_224_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224_3(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224_3(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false -} - -hash_224_3 :: proc { - hash_stream_224_3, - hash_file_224_3, - hash_bytes_224_3, - hash_string_224_3, - hash_bytes_to_buffer_224_3, - hash_string_to_buffer_224_3, -} - -// hash_string_224_4 will hash the given input and return the -// computed hash -hash_string_224_4 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224_4(transmute([]byte)(data)) -} - -// hash_bytes_224_4 will hash the given input and return the -// computed hash -hash_bytes_224_4 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_224_4 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_224_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_224_4 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_224_4 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_224_4 will read the stream in chunks and compute a -// hash from its contents -hash_stream_224_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 4 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_224_4 will read the file provided by the given handle -// and compute a hash -hash_file_224_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224_4(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224_4(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false -} - -hash_224_4 :: proc { - hash_stream_224_4, - hash_file_224_4, - hash_bytes_224_4, - hash_string_224_4, - hash_bytes_to_buffer_224_4, - hash_string_to_buffer_224_4, -} - -// hash_string_224_5 will hash the given input and return the -// computed hash -hash_string_224_5 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224_5(transmute([]byte)(data)) -} - -// hash_bytes_224_5 will hash the given input and return the -// computed hash -hash_bytes_224_5 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_224_5 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_224_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_224_5 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_224_5 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_224_5 will read the stream in chunks and compute a -// hash from its contents -hash_stream_224_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: Haval_Context - ctx.hashbitlen = 224 - ctx.rounds = 5 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_224_5 will read the file provided by the given handle -// and compute a hash -hash_file_224_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224_5(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224_5(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false -} - -hash_224_5 :: proc { - hash_stream_224_5, - hash_file_224_5, - hash_bytes_224_5, - hash_string_224_5, - hash_bytes_to_buffer_224_5, - hash_string_to_buffer_224_5, -} - -// hash_string_256_3 will hash the given input and return the -// computed hash -hash_string_256_3 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256_3(transmute([]byte)(data)) -} - -// hash_bytes_256_3 will hash the given input and return the -// computed hash -hash_bytes_256_3 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256_3 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256_3 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256_3 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256_3 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 3 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_256_3 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 3 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256_3 will read the file provided by the given handle -// and compute a hash -hash_file_256_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256_3(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256_3(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256_3 :: proc { - hash_stream_256_3, - hash_file_256_3, - hash_bytes_256_3, - hash_string_256_3, - hash_bytes_to_buffer_256_3, - hash_string_to_buffer_256_3, -} - -// hash_string_256_4 will hash the given input and return the -// computed hash -hash_string_256_4 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256_4(transmute([]byte)(data)) -} - -// hash_bytes_256_4 will hash the given input and return the -// computed hash -hash_bytes_256_4 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256_4 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256_4 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256_4 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256_4 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 4 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_256_4 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 4 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256_4 will read the file provided by the given handle -// and compute a hash -hash_file_256_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256_4(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256_4(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256_4 :: proc { - hash_stream_256_4, - hash_file_256_4, - hash_bytes_256_4, - hash_string_256_4, - hash_bytes_to_buffer_256_4, - hash_string_to_buffer_256_4, -} - -// hash_string_256_5 will hash the given input and return the -// computed hash -hash_string_256_5 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256_5(transmute([]byte)(data)) -} - -// hash_bytes_256_5 will hash the given input and return the -// computed hash -hash_bytes_256_5 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256_5 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256_5 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256_5 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256_5 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 5 - init(&ctx) - ctx.str_len = u32(len(data)) - update(&ctx, data) - final(&ctx, hash) -} - - -// hash_stream_256_5 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Haval_Context - ctx.hashbitlen = 256 - ctx.rounds = 5 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - ctx.str_len = u32(len(buf[:read])) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256_5 will read the file provided by the given handle -// and compute a hash -hash_file_256_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256_5(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256_5(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256_5 :: proc { - hash_stream_256_5, - hash_file_256_5, - hash_bytes_256_5, - hash_string_256_5, - hash_bytes_to_buffer_256_5, - hash_string_to_buffer_256_5, -} - -/* - Low level API -*/ - -init :: proc(ctx: ^Haval_Context) { - assert(ctx.hashbitlen == 128 || ctx.hashbitlen == 160 || ctx.hashbitlen == 192 || ctx.hashbitlen == 224 || ctx.hashbitlen == 256, "hashbitlen must be set to 128, 160, 192, 224 or 256") - assert(ctx.rounds == 3 || ctx.rounds == 4 || ctx.rounds == 5, "rounds must be set to 3, 4 or 5") - ctx.fingerprint[0] = 0x243f6a88 - ctx.fingerprint[1] = 0x85a308d3 - ctx.fingerprint[2] = 0x13198a2e - ctx.fingerprint[3] = 0x03707344 - ctx.fingerprint[4] = 0xa4093822 - ctx.fingerprint[5] = 0x299f31d0 - ctx.fingerprint[6] = 0x082efa98 - ctx.fingerprint[7] = 0xec4e6c89 -} - -// @note(zh): Make sure to set ctx.str_len to the remaining buffer size before calling this proc - e.g. ctx.str_len = u32(len(data)) -update :: proc(ctx: ^Haval_Context, data: []byte) { - i: u32 - rmd_len := u32((ctx.count[0] >> 3) & 0x7f) - fill_len := 128 - rmd_len - str_len := ctx.str_len - - ctx.count[0] += str_len << 3 - if ctx.count[0] < (str_len << 3) { - ctx.count[1] += 1 - } - ctx.count[1] += str_len >> 29 - - when ODIN_ENDIAN == .Little { - if rmd_len + str_len >= 128 { - copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len]) - block(ctx, ctx.rounds) - for i = fill_len; i + 127 < str_len; i += 128 { - copy(util.slice_to_bytes(ctx.block[:]), data[i:128]) - block(ctx, ctx.rounds) - } - rmd_len = 0 - } else { - i = 0 - } - copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[i:]) - } else { - if rmd_len + str_len >= 128 { - copy(ctx.remainder[rmd_len:], data[:fill_len]) - CH2UINT(ctx.remainder[:], ctx.block[:]) - block(ctx, ctx.rounds) - for i = fill_len; i + 127 < str_len; i += 128 { - copy(ctx.remainder[:], data[i:128]) - CH2UINT(ctx.remainder[:], ctx.block[:]) - block(ctx, ctx.rounds) - } - rmd_len = 0 - } else { - i = 0 - } - copy(ctx.remainder[rmd_len:], data[i:]) - } -} - -final :: proc(ctx: ^Haval_Context, hash: []byte) { - pad_len: u32 - tail: [10]byte - - tail[0] = byte(ctx.hashbitlen & 0x3) << 6 | byte(ctx.rounds & 0x7) << 3 | (VERSION & 0x7) - tail[1] = byte(ctx.hashbitlen >> 2) & 0xff - - UINT2CH(ctx.count[:], util.slice_to_bytes(tail[2:]), 2) - rmd_len := (ctx.count[0] >> 3) & 0x7f - if rmd_len < 118 { - pad_len = 118 - rmd_len - } else { - pad_len = 246 - rmd_len - } - - ctx.str_len = pad_len - update(ctx, PADDING[:]) - ctx.str_len = 10 - update(ctx, tail[:]) - tailor(ctx, ctx.hashbitlen) - UINT2CH(ctx.fingerprint[:], hash, ctx.hashbitlen >> 5) - - mem.set(ctx, 0, size_of(ctx)) -} - -/* - HAVAL implementation -*/ - -VERSION :: 1 - -Haval_Context :: struct { - count: [2]u32, - fingerprint: [8]u32, - block: [32]u32, - remainder: [128]byte, - rounds: u32, - hashbitlen: u32, - str_len: u32, -} - -PADDING := [128]byte { - 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -} - -F_1 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { - return ((x1) & ((x0) ~ (x4)) ~ (x2) & (x5) ~ (x3) & (x6) ~ (x0)) -} - -F_2 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { - return ((x2) & ((x1) & ~(x3) ~ (x4) & (x5) ~ (x6) ~ (x0)) ~ (x4) & ((x1) ~ (x5)) ~ (x3) & (x5) ~ (x0)) -} - -F_3 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { - return ((x3) & ((x1) & (x2) ~ (x6) ~ (x0)) ~ (x1) & (x4) ~ (x2) & (x5) ~ (x0)) -} - -F_4 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { - return ((x4) & ((x5) & ~(x2) ~ (x3) & ~(x6) ~ (x1) ~ (x6) ~ (x0)) ~ (x3) & ((x1) & (x2) ~ (x5) ~ (x6)) ~ (x2) & (x6) ~ (x0)) -} - -F_5 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { - return ((x0) & ((x1) & (x2) & (x3) ~ ~(x5)) ~ (x1) & (x4) ~ (x2) & (x5) ~ (x3) & (x6)) -} - -FPHI_1 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { - switch rounds { - case 3: return F_1(x1, x0, x3, x5, x6, x2, x4) - case 4: return F_1(x2, x6, x1, x4, x5, x3, x0) - case 5: return F_1(x3, x4, x1, x0, x5, x2, x6) - case: assert(rounds < 3 || rounds > 5, "Rounds count not supported!") - } - return 0 -} - -FPHI_2 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { - switch rounds { - case 3: return F_2(x4, x2, x1, x0, x5, x3, x6) - case 4: return F_2(x3, x5, x2, x0, x1, x6, x4) - case 5: return F_2(x6, x2, x1, x0, x3, x4, x5) - case: assert(rounds < 3 || rounds > 5, "Rounds count not supported!") - } - return 0 -} - -FPHI_3 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { - switch rounds { - case 3: return F_3(x6, x1, x2, x3, x4, x5, x0) - case 4: return F_3(x1, x4, x3, x6, x0, x2, x5) - case 5: return F_3(x2, x6, x0, x4, x3, x1, x5) - case: assert(rounds < 3 || rounds > 5, "Rounds count not supported!") - } - return 0 -} - -FPHI_4 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { - switch rounds { - case 4: return F_4(x6, x4, x0, x5, x2, x1, x3) - case 5: return F_4(x1, x5, x3, x2, x0, x4, x6) - case: assert(rounds < 4 || rounds > 5, "Rounds count not supported!") - } - return 0 -} - -FPHI_5 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { - switch rounds { - case 5: return F_5(x2, x5, x0, x6, x4, x3, x1) - case: assert(rounds != 5, "Rounds count not supported!") - } - return 0 -} - -FF_1 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, rounds: u32) -> u32 { - tmp := FPHI_1(x6, x5, x4, x3, x2, x1, x0, rounds) - x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w - return x8 -} - -FF_2 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { - tmp := FPHI_2(x6, x5, x4, x3, x2, x1, x0, rounds) - x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c - return x8 -} - -FF_3 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { - tmp := FPHI_3(x6, x5, x4, x3, x2, x1, x0, rounds) - x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c - return x8 -} - -FF_4 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { - tmp := FPHI_4(x6, x5, x4, x3, x2, x1, x0, rounds) - x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c - return x8 -} - -FF_5 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { - tmp := FPHI_5(x6, x5, x4, x3, x2, x1, x0, rounds) - x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c - return x8 -} - -CH2UINT :: #force_inline proc "contextless" (str: []byte, word: []u32) { - for _, i in word[:32] { - word[i] = u32(str[i*4+0]) << 0 | u32(str[i*4+1]) << 8 | u32(str[i*4+2]) << 16 | u32(str[i*4+3]) << 24 - } -} - -UINT2CH :: #force_inline proc "contextless" (word: []u32, str: []byte, wlen: u32) { - for _, i in word[:wlen] { - str[i*4+0] = byte(word[i] >> 0) & 0xff - str[i*4+1] = byte(word[i] >> 8) & 0xff - str[i*4+2] = byte(word[i] >> 16) & 0xff - str[i*4+3] = byte(word[i] >> 24) & 0xff - } -} - -block :: proc(ctx: ^Haval_Context, rounds: u32) { - t0, t1, t2, t3 := ctx.fingerprint[0], ctx.fingerprint[1], ctx.fingerprint[2], ctx.fingerprint[3] - t4, t5, t6, t7 := ctx.fingerprint[4], ctx.fingerprint[5], ctx.fingerprint[6], ctx.fingerprint[7] - w := ctx.block - - t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[ 0], rounds) - t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[ 1], rounds) - t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[ 2], rounds) - t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[ 3], rounds) - t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[ 4], rounds) - t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[ 5], rounds) - t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[ 6], rounds) - t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[ 7], rounds) - - t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[ 8], rounds) - t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[ 9], rounds) - t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[10], rounds) - t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[11], rounds) - t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[12], rounds) - t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[13], rounds) - t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[14], rounds) - t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[15], rounds) - - t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[16], rounds) - t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[17], rounds) - t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[18], rounds) - t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[19], rounds) - t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[20], rounds) - t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[21], rounds) - t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[22], rounds) - t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[23], rounds) - - t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[24], rounds) - t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[25], rounds) - t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[26], rounds) - t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[27], rounds) - t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[28], rounds) - t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[29], rounds) - t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[30], rounds) - t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[31], rounds) - - t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[ 5], 0x452821e6, rounds) - t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[14], 0x38d01377, rounds) - t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[26], 0xbe5466cf, rounds) - t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[18], 0x34e90c6c, rounds) - t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[11], 0xc0ac29b7, rounds) - t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[28], 0xc97c50dd, rounds) - t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[ 7], 0x3f84d5b5, rounds) - t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[16], 0xb5470917, rounds) - - t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[ 0], 0x9216d5d9, rounds) - t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[23], 0x8979fb1b, rounds) - t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[20], 0xd1310ba6, rounds) - t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[22], 0x98dfb5ac, rounds) - t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[ 1], 0x2ffd72db, rounds) - t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[10], 0xd01adfb7, rounds) - t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[ 4], 0xb8e1afed, rounds) - t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[ 8], 0x6a267e96, rounds) - - t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[30], 0xba7c9045, rounds) - t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[ 3], 0xf12c7f99, rounds) - t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[21], 0x24a19947, rounds) - t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[ 9], 0xb3916cf7, rounds) - t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[17], 0x0801f2e2, rounds) - t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[24], 0x858efc16, rounds) - t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[29], 0x636920d8, rounds) - t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[ 6], 0x71574e69, rounds) - - t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[19], 0xa458fea3, rounds) - t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[12], 0xf4933d7e, rounds) - t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[15], 0x0d95748f, rounds) - t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[13], 0x728eb658, rounds) - t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[ 2], 0x718bcd58, rounds) - t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[25], 0x82154aee, rounds) - t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[31], 0x7b54a41d, rounds) - t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[27], 0xc25a59b5, rounds) - - t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[19], 0x9c30d539, rounds) - t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[ 9], 0x2af26013, rounds) - t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[ 4], 0xc5d1b023, rounds) - t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[20], 0x286085f0, rounds) - t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[28], 0xca417918, rounds) - t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[17], 0xb8db38ef, rounds) - t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[ 8], 0x8e79dcb0, rounds) - t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[22], 0x603a180e, rounds) - - t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[29], 0x6c9e0e8b, rounds) - t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[14], 0xb01e8a3e, rounds) - t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[25], 0xd71577c1, rounds) - t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[12], 0xbd314b27, rounds) - t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[24], 0x78af2fda, rounds) - t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[30], 0x55605c60, rounds) - t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[16], 0xe65525f3, rounds) - t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[26], 0xaa55ab94, rounds) - - t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[31], 0x57489862, rounds) - t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[15], 0x63e81440, rounds) - t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[ 7], 0x55ca396a, rounds) - t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[ 3], 0x2aab10b6, rounds) - t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[ 1], 0xb4cc5c34, rounds) - t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[ 0], 0x1141e8ce, rounds) - t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[18], 0xa15486af, rounds) - t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[27], 0x7c72e993, rounds) - - t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[13], 0xb3ee1411, rounds) - t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[ 6], 0x636fbc2a, rounds) - t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[21], 0x2ba9c55d, rounds) - t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[10], 0x741831f6, rounds) - t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[23], 0xce5c3e16, rounds) - t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[11], 0x9b87931e, rounds) - t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[ 5], 0xafd6ba33, rounds) - t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[ 2], 0x6c24cf5c, rounds) - - if rounds >= 4 { - t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[24], 0x7a325381, rounds) - t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[ 4], 0x28958677, rounds) - t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[ 0], 0x3b8f4898, rounds) - t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[14], 0x6b4bb9af, rounds) - t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[ 2], 0xc4bfe81b, rounds) - t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[ 7], 0x66282193, rounds) - t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[28], 0x61d809cc, rounds) - t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[23], 0xfb21a991, rounds) - - t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[26], 0x487cac60, rounds) - t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[ 6], 0x5dec8032, rounds) - t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[30], 0xef845d5d, rounds) - t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[20], 0xe98575b1, rounds) - t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[18], 0xdc262302, rounds) - t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[25], 0xeb651b88, rounds) - t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[19], 0x23893e81, rounds) - t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[ 3], 0xd396acc5, rounds) - - t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[22], 0x0f6d6ff3, rounds) - t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[11], 0x83f44239, rounds) - t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[31], 0x2e0b4482, rounds) - t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[21], 0xa4842004, rounds) - t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[ 8], 0x69c8f04a, rounds) - t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[27], 0x9e1f9b5e, rounds) - t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[12], 0x21c66842, rounds) - t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[ 9], 0xf6e96c9a, rounds) - - t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[ 1], 0x670c9c61, rounds) - t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[29], 0xabd388f0, rounds) - t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[ 5], 0x6a51a0d2, rounds) - t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[15], 0xd8542f68, rounds) - t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[17], 0x960fa728, rounds) - t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[10], 0xab5133a3, rounds) - t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[16], 0x6eef0b6c, rounds) - t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[13], 0x137a3be4, rounds) - } - - if rounds == 5 { - t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[27], 0xba3bf050, rounds) - t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[ 3], 0x7efb2a98, rounds) - t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[21], 0xa1f1651d, rounds) - t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[26], 0x39af0176, rounds) - t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[17], 0x66ca593e, rounds) - t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[11], 0x82430e88, rounds) - t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[20], 0x8cee8619, rounds) - t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[29], 0x456f9fb4, rounds) - - t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[19], 0x7d84a5c3, rounds) - t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[ 0], 0x3b8b5ebe, rounds) - t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[12], 0xe06f75d8, rounds) - t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[ 7], 0x85c12073, rounds) - t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[13], 0x401a449f, rounds) - t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[ 8], 0x56c16aa6, rounds) - t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[31], 0x4ed3aa62, rounds) - t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[10], 0x363f7706, rounds) - - t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[ 5], 0x1bfedf72, rounds) - t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[ 9], 0x429b023d, rounds) - t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[14], 0x37d0d724, rounds) - t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[30], 0xd00a1248, rounds) - t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[18], 0xdb0fead3, rounds) - t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[ 6], 0x49f1c09b, rounds) - t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[28], 0x075372c9, rounds) - t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[24], 0x80991b7b, rounds) - - t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[ 2], 0x25d479d8, rounds) - t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[23], 0xf6e8def7, rounds) - t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[16], 0xe3fe501a, rounds) - t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[22], 0xb6794c3b, rounds) - t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[ 4], 0x976ce0bd, rounds) - t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[ 1], 0x04c006ba, rounds) - t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[25], 0xc1a94fb6, rounds) - t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[15], 0x409f60c4, rounds) - } - - ctx.fingerprint[0] += t0 - ctx.fingerprint[1] += t1 - ctx.fingerprint[2] += t2 - ctx.fingerprint[3] += t3 - ctx.fingerprint[4] += t4 - ctx.fingerprint[5] += t5 - ctx.fingerprint[6] += t6 - ctx.fingerprint[7] += t7 -} - -tailor :: proc(ctx: ^Haval_Context, size: u32) { - temp: u32 - switch size { - case 128: - temp = (ctx.fingerprint[7] & 0x000000ff) | - (ctx.fingerprint[6] & 0xff000000) | - (ctx.fingerprint[5] & 0x00ff0000) | - (ctx.fingerprint[4] & 0x0000ff00) - ctx.fingerprint[0] += util.ROTR32(temp, 8) - - temp = (ctx.fingerprint[7] & 0x0000ff00) | - (ctx.fingerprint[6] & 0x000000ff) | - (ctx.fingerprint[5] & 0xff000000) | - (ctx.fingerprint[4] & 0x00ff0000) - ctx.fingerprint[1] += util.ROTR32(temp, 16) - - temp = (ctx.fingerprint[7] & 0x00ff0000) | - (ctx.fingerprint[6] & 0x0000ff00) | - (ctx.fingerprint[5] & 0x000000ff) | - (ctx.fingerprint[4] & 0xff000000) - ctx.fingerprint[2] += util.ROTR32(temp, 24) - - temp = (ctx.fingerprint[7] & 0xff000000) | - (ctx.fingerprint[6] & 0x00ff0000) | - (ctx.fingerprint[5] & 0x0000ff00) | - (ctx.fingerprint[4] & 0x000000ff) - ctx.fingerprint[3] += temp - case 160: - temp = (ctx.fingerprint[7] & u32(0x3f)) | - (ctx.fingerprint[6] & u32(0x7f << 25)) | - (ctx.fingerprint[5] & u32(0x3f << 19)) - ctx.fingerprint[0] += util.ROTR32(temp, 19) - - temp = (ctx.fingerprint[7] & u32(0x3f << 6)) | - (ctx.fingerprint[6] & u32(0x3f)) | - (ctx.fingerprint[5] & u32(0x7f << 25)) - ctx.fingerprint[1] += util.ROTR32(temp, 25) - - temp = (ctx.fingerprint[7] & u32(0x7f << 12)) | - (ctx.fingerprint[6] & u32(0x3f << 6)) | - (ctx.fingerprint[5] & u32(0x3f)) - ctx.fingerprint[2] += temp - - temp = (ctx.fingerprint[7] & u32(0x3f << 19)) | - (ctx.fingerprint[6] & u32(0x7f << 12)) | - (ctx.fingerprint[5] & u32(0x3f << 6)) - ctx.fingerprint[3] += temp >> 6 - - temp = (ctx.fingerprint[7] & u32(0x7f << 25)) | - (ctx.fingerprint[6] & u32(0x3f << 19)) | - (ctx.fingerprint[5] & u32(0x7f << 12)) - ctx.fingerprint[4] += temp >> 12 - case 192: - temp = (ctx.fingerprint[7] & u32(0x1f)) | - (ctx.fingerprint[6] & u32(0x3f << 26)) - ctx.fingerprint[0] += util.ROTR32(temp, 26) - - temp = (ctx.fingerprint[7] & u32(0x1f << 5)) | - (ctx.fingerprint[6] & u32(0x1f)) - ctx.fingerprint[1] += temp - - temp = (ctx.fingerprint[7] & u32(0x3f << 10)) | - (ctx.fingerprint[6] & u32(0x1f << 5)) - ctx.fingerprint[2] += temp >> 5 - - temp = (ctx.fingerprint[7] & u32(0x1f << 16)) | - (ctx.fingerprint[6] & u32(0x3f << 10)) - ctx.fingerprint[3] += temp >> 10 - - temp = (ctx.fingerprint[7] & u32(0x1f << 21)) | - (ctx.fingerprint[6] & u32(0x1f << 16)) - ctx.fingerprint[4] += temp >> 16 - - temp = (ctx.fingerprint[7] & u32(0x3f << 26)) | - (ctx.fingerprint[6] & u32(0x1f << 21)) - ctx.fingerprint[5] += temp >> 21 - case 224: - ctx.fingerprint[0] += (ctx.fingerprint[7] >> 27) & 0x1f - ctx.fingerprint[1] += (ctx.fingerprint[7] >> 22) & 0x1f - ctx.fingerprint[2] += (ctx.fingerprint[7] >> 18) & 0x0f - ctx.fingerprint[3] += (ctx.fingerprint[7] >> 13) & 0x1f - ctx.fingerprint[4] += (ctx.fingerprint[7] >> 9) & 0x0f - ctx.fingerprint[5] += (ctx.fingerprint[7] >> 4) & 0x1f - ctx.fingerprint[6] += ctx.fingerprint[7] & 0x0f - } -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 70ce5629c..ea2034b53 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -27,7 +27,6 @@ import blake2b "core:crypto/blake2b" import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" import chacha20poly1305 "core:crypto/chacha20poly1305" -import haval "core:crypto/haval" import jh "core:crypto/jh" import keccak "core:crypto/keccak" import md2 "core:crypto/md2" @@ -151,7 +150,6 @@ _ :: blake2b _ :: blake2s _ :: chacha20 _ :: chacha20poly1305 -_ :: haval _ :: jh _ :: keccak _ :: md2 diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 9f88be1b5..982ec766d 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -33,7 +33,6 @@ import "core:crypto/tiger2" import "core:crypto/streebog" import "core:crypto/sm3" import "core:crypto/jh" -import "core:crypto/haval" import "core:crypto/siphash" import "core:os" @@ -99,11 +98,6 @@ main :: proc() { test_jh_256(&t) test_jh_384(&t) test_jh_512(&t) - test_haval_128(&t) - test_haval_160(&t) - test_haval_192(&t) - test_haval_224(&t) - test_haval_256(&t) test_siphash_2_4(&t) // "modern" crypto tests @@ -819,171 +813,6 @@ test_jh_512 :: proc(t: ^testing.T) { } } -@(test) -test_haval_128 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, - TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, - TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, - TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, - TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_128_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, - TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_128_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, - TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_128_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_haval_160 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, - TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, - TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, - TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, - TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_160_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, - TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_160_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, - TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_160_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_haval_192 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, - TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_192_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, - TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_192_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, - TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_192_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_haval_224 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, - TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_224_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, - TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_224_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, - TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_224_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_haval_256 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, - TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_256_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, - TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_256_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, - TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_256_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_siphash_2_4 :: proc(t: ^testing.T) { // Test vectors from From a99c0b3e4a3a7645d819be21d10e01559384c280 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:40:57 +0900 Subject: [PATCH 093/160] core/crypto/jh: Remove, use SHA-3 --- core/crypto/README.md | 1 - core/crypto/jh/jh.odin | 584 ------------------------ examples/all/all_main.odin | 2 - tests/core/crypto/test_core_crypto.odin | 61 --- 4 files changed, 648 deletions(-) delete mode 100644 core/crypto/jh/jh.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index 3b02be26a..229522dc4 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -10,7 +10,6 @@ Please see the chart below for the options. |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | -| [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ | | [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | diff --git a/core/crypto/jh/jh.odin b/core/crypto/jh/jh.odin deleted file mode 100644 index 5dc6c4e6b..000000000 --- a/core/crypto/jh/jh.odin +++ /dev/null @@ -1,584 +0,0 @@ -package jh - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the JH hashing algorithm, as defined in -*/ - -import "core:os" -import "core:io" - -/* - High level API -*/ - -DIGEST_SIZE_224 :: 28 -DIGEST_SIZE_256 :: 32 -DIGEST_SIZE_384 :: 48 -DIGEST_SIZE_512 :: 64 - -// hash_string_224 will hash the given input and return the -// computed hash -hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { - return hash_bytes_224(transmute([]byte)(data)) -} - -// hash_bytes_224 will hash the given input and return the -// computed hash -hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { - hash: [DIGEST_SIZE_224]byte - ctx: Jh_Context - ctx.hashbitlen = 224 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_224 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_224(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_224 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: Jh_Context - ctx.hashbitlen = 224 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_224 will read the stream in chunks and compute a -// hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { - hash: [DIGEST_SIZE_224]byte - ctx: Jh_Context - ctx.hashbitlen = 224 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_224 will read the file provided by the given handle -// and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { - if !load_at_once { - return hash_stream_224(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_224(buf[:]), ok - } - } - return [DIGEST_SIZE_224]byte{}, false -} - -hash_224 :: proc { - hash_stream_224, - hash_file_224, - hash_bytes_224, - hash_string_224, - hash_bytes_to_buffer_224, - hash_string_to_buffer_224, -} - -// hash_string_256 will hash the given input and return the -// computed hash -hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) -} - -// hash_bytes_256 will hash the given input and return the -// computed hash -hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Jh_Context - ctx.hashbitlen = 256 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Jh_Context - ctx.hashbitlen = 256 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_256 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Jh_Context - ctx.hashbitlen = 256 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256 will read the file provided by the given handle -// and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, -} - -// hash_string_384 will hash the given input and return the -// computed hash -hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { - return hash_bytes_384(transmute([]byte)(data)) -} - -// hash_bytes_384 will hash the given input and return the -// computed hash -hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { - hash: [DIGEST_SIZE_384]byte - ctx: Jh_Context - ctx.hashbitlen = 384 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_384 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_384(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_384 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: Jh_Context - ctx.hashbitlen = 384 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_384 will read the stream in chunks and compute a -// hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { - hash: [DIGEST_SIZE_384]byte - ctx: Jh_Context - ctx.hashbitlen = 384 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_384 will read the file provided by the given handle -// and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { - if !load_at_once { - return hash_stream_384(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_384(buf[:]), ok - } - } - return [DIGEST_SIZE_384]byte{}, false -} - -hash_384 :: proc { - hash_stream_384, - hash_file_384, - hash_bytes_384, - hash_string_384, - hash_bytes_to_buffer_384, - hash_string_to_buffer_384, -} - -// hash_string_512 will hash the given input and return the -// computed hash -hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) -} - -// hash_bytes_512 will hash the given input and return the -// computed hash -hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: Jh_Context - ctx.hashbitlen = 512 - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_512 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_512 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: Jh_Context - ctx.hashbitlen = 512 - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_512 will read the stream in chunks and compute a -// hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: Jh_Context - ctx.hashbitlen = 512 - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_512 will read the file provided by the given handle -// and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false -} - -hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, -} - -/* - Low level API -*/ - -init :: proc(ctx: ^Jh_Context) { - assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512") - ctx.H[1] = byte(ctx.hashbitlen) & 0xff - ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff - F8(ctx) -} - -update :: proc(ctx: ^Jh_Context, data: []byte) { - databitlen := u64(len(data)) * 8 - ctx.databitlen += databitlen - i := u64(0) - - if (ctx.buffer_size > 0) && ((ctx.buffer_size + databitlen) < 512) { - if (databitlen & 7) == 0 { - copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) - } else { - copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3) + 1]) - } - ctx.buffer_size += databitlen - databitlen = 0 - } - - if (ctx.buffer_size > 0 ) && ((ctx.buffer_size + databitlen) >= 512) { - copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) - i = 64 - (ctx.buffer_size >> 3) - databitlen = databitlen - (512 - ctx.buffer_size) - F8(ctx) - ctx.buffer_size = 0 - } - - for databitlen >= 512 { - copy(ctx.buffer[:], data[i:i + 64]) - F8(ctx) - i += 64 - databitlen -= 512 - } - - if databitlen > 0 { - if (databitlen & 7) == 0 { - copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3)]) - } else { - copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3) + 1]) - } - ctx.buffer_size = databitlen - } -} - -final :: proc(ctx: ^Jh_Context, hash: []byte) { - if ctx.databitlen & 0x1ff == 0 { - for i := 0; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - ctx.buffer[0] = 0x80 - ctx.buffer[63] = byte(ctx.databitlen) & 0xff - ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff - ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff - ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff - ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff - ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff - ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff - ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff - F8(ctx) - } else { - if ctx.buffer_size & 7 == 0 { - for i := (ctx.databitlen & 0x1ff) >> 3; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - } else { - for i := ((ctx.databitlen & 0x1ff) >> 3) + 1; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - } - ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7)) - F8(ctx) - for i := 0; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - ctx.buffer[63] = byte(ctx.databitlen) & 0xff - ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff - ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff - ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff - ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff - ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff - ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff - ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff - F8(ctx) - } - switch ctx.hashbitlen { - case 224: copy(hash[:], ctx.H[100:128]) - case 256: copy(hash[:], ctx.H[96:128]) - case 384: copy(hash[:], ctx.H[80:128]) - case 512: copy(hash[:], ctx.H[64:128]) - } -} - -/* - JH implementation -*/ - -ROUNDCONSTANT_ZERO := [64]byte { - 0x6, 0xa, 0x0, 0x9, 0xe, 0x6, 0x6, 0x7, - 0xf, 0x3, 0xb, 0xc, 0xc, 0x9, 0x0, 0x8, - 0xb, 0x2, 0xf, 0xb, 0x1, 0x3, 0x6, 0x6, - 0xe, 0xa, 0x9, 0x5, 0x7, 0xd, 0x3, 0xe, - 0x3, 0xa, 0xd, 0xe, 0xc, 0x1, 0x7, 0x5, - 0x1, 0x2, 0x7, 0x7, 0x5, 0x0, 0x9, 0x9, - 0xd, 0xa, 0x2, 0xf, 0x5, 0x9, 0x0, 0xb, - 0x0, 0x6, 0x6, 0x7, 0x3, 0x2, 0x2, 0xa, -} - -SBOX := [2][16]byte { - {9, 0, 4, 11, 13, 12, 3, 15, 1, 10, 2, 6, 7, 5, 8, 14}, - {3, 12, 6, 13, 5, 7, 1, 9, 15, 2, 0, 4, 11, 10, 14, 8}, -} - -Jh_Context :: struct { - hashbitlen: int, - databitlen: u64, - buffer_size: u64, - H: [128]byte, - A: [256]byte, - roundconstant: [64]byte, - buffer: [64]byte, -} - -E8_finaldegroup :: proc(ctx: ^Jh_Context) { - t0,t1,t2,t3: byte - tem: [256]byte - for i := 0; i < 128; i += 1 { - tem[i] = ctx.A[i << 1] - tem[i + 128] = ctx.A[(i << 1) + 1] - } - for i := 0; i < 128; i += 1 { - ctx.H[i] = 0 - } - for i := 0; i < 256; i += 1 { - t0 = (tem[i] >> 3) & 1 - t1 = (tem[i] >> 2) & 1 - t2 = (tem[i] >> 1) & 1 - t3 = (tem[i] >> 0) & 1 - - ctx.H[uint(i) >> 3] |= t0 << (7 - (uint(i) & 7)) - ctx.H[(uint(i) + 256) >> 3] |= t1 << (7 - (uint(i) & 7)) - ctx.H[(uint(i) + 512) >> 3] |= t2 << (7 - (uint(i) & 7)) - ctx.H[(uint(i) + 768) >> 3] |= t3 << (7 - (uint(i) & 7)) - } -} - -update_roundconstant :: proc(ctx: ^Jh_Context) { - tem: [64]byte - t: byte - for i := 0; i < 64; i += 1 { - tem[i] = SBOX[0][ctx.roundconstant[i]] - } - for i := 0; i < 64; i += 2 { - tem[i + 1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf - tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf - } - for i := 0; i < 64; i += 4 { - t = tem[i + 2] - tem[i + 2] = tem[i + 3] - tem[i + 3] = t - } - for i := 0; i < 32; i += 1 { - ctx.roundconstant[i] = tem[i << 1] - ctx.roundconstant[i + 32] = tem[(i << 1) + 1] - } - for i := 32; i < 64; i += 2 { - t = ctx.roundconstant[i] - ctx.roundconstant[i] = ctx.roundconstant[i + 1] - ctx.roundconstant[i + 1] = t - } -} - -R8 :: proc(ctx: ^Jh_Context) { - t: byte - tem, roundconstant_expanded: [256]byte - for i := u32(0); i < 256; i += 1 { - roundconstant_expanded[i] = (ctx.roundconstant[i >> 2] >> (3 - (i & 3)) ) & 1 - } - for i := 0; i < 256; i += 1 { - tem[i] = SBOX[roundconstant_expanded[i]][ctx.A[i]] - } - for i := 0; i < 256; i += 2 { - tem[i+1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf - tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf - } - for i := 0; i < 256; i += 4 { - t = tem[i + 2] - tem[i+2] = tem[i + 3] - tem[i+3] = t - } - for i := 0; i < 128; i += 1 { - ctx.A[i] = tem[i << 1] - ctx.A[i + 128] = tem[(i << 1) + 1] - } - for i := 128; i < 256; i += 2 { - t = ctx.A[i] - ctx.A[i] = ctx.A[i + 1] - ctx.A[i + 1] = t - } -} - -E8_initialgroup :: proc(ctx: ^Jh_Context) { - t0, t1, t2, t3: byte - tem: [256]byte - for i := u32(0); i < 256; i += 1 { - t0 = (ctx.H[i >> 3] >> (7 - (i & 7))) & 1 - t1 = (ctx.H[(i + 256) >> 3] >> (7 - (i & 7))) & 1 - t2 = (ctx.H[(i + 512) >> 3] >> (7 - (i & 7))) & 1 - t3 = (ctx.H[(i + 768) >> 3] >> (7 - (i & 7))) & 1 - tem[i] = (t0 << 3) | (t1 << 2) | (t2 << 1) | (t3 << 0) - } - for i := 0; i < 128; i += 1 { - ctx.A[i << 1] = tem[i] - ctx.A[(i << 1) + 1] = tem[i + 128] - } -} - -E8 :: proc(ctx: ^Jh_Context) { - for i := 0; i < 64; i += 1 { - ctx.roundconstant[i] = ROUNDCONSTANT_ZERO[i] - } - E8_initialgroup(ctx) - for i := 0; i < 42; i += 1 { - R8(ctx) - update_roundconstant(ctx) - } - E8_finaldegroup(ctx) -} - -F8 :: proc(ctx: ^Jh_Context) { - for i := 0; i < 64; i += 1 { - ctx.H[i] ~= ctx.buffer[i] - } - E8(ctx) - for i := 0; i < 64; i += 1 { - ctx.H[i + 64] ~= ctx.buffer[i] - } -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index ea2034b53..0b5cde5e9 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -27,7 +27,6 @@ import blake2b "core:crypto/blake2b" import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" import chacha20poly1305 "core:crypto/chacha20poly1305" -import jh "core:crypto/jh" import keccak "core:crypto/keccak" import md2 "core:crypto/md2" import md4 "core:crypto/md4" @@ -150,7 +149,6 @@ _ :: blake2b _ :: blake2s _ :: chacha20 _ :: chacha20poly1305 -_ :: jh _ :: keccak _ :: md2 _ :: md4 diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 982ec766d..979ca715f 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -32,7 +32,6 @@ import "core:crypto/tiger" import "core:crypto/tiger2" import "core:crypto/streebog" import "core:crypto/sm3" -import "core:crypto/jh" import "core:crypto/siphash" import "core:os" @@ -94,10 +93,6 @@ main :: proc() { test_tiger2_160(&t) test_tiger2_192(&t) test_sm3(&t) - test_jh_224(&t) - test_jh_256(&t) - test_jh_384(&t) - test_jh_512(&t) test_siphash_2_4(&t) // "modern" crypto tests @@ -757,62 +752,6 @@ test_sm3 :: proc(t: ^testing.T) { } } -@(test) -test_jh_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, - TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, - TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_jh_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, - TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, - TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_jh_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, - TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, - TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_jh_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, - TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, - TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_siphash_2_4 :: proc(t: ^testing.T) { // Test vectors from From 97b066f11262ab055dfd4d8d2d304d0c2fc2e8f8 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:42:44 +0900 Subject: [PATCH 094/160] core/crypto/md2: Remove, badly broken --- core/crypto/README.md | 1 - core/crypto/md2/md2.odin | 182 ------------------------ examples/all/all_main.odin | 2 - tests/core/crypto/test_core_crypto.odin | 21 --- 4 files changed, 206 deletions(-) delete mode 100644 core/crypto/md2/md2.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index 229522dc4..28d7cc94b 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -11,7 +11,6 @@ Please see the chart below for the options. | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | -| [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ | | [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | | [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | | [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | diff --git a/core/crypto/md2/md2.odin b/core/crypto/md2/md2.odin deleted file mode 100644 index 4942183e1..000000000 --- a/core/crypto/md2/md2.odin +++ /dev/null @@ -1,182 +0,0 @@ -package md2 - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the MD2 hashing algorithm, as defined in RFC 1319 -*/ - -import "core:os" -import "core:io" - -/* - High level API -*/ - -DIGEST_SIZE :: 16 - -// hash_string will hash the given input and return the -// computed hash -hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) -} - -// hash_bytes will hash the given input and return the -// computed hash -hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: Md2_Context - // init(&ctx) No-op - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: Md2_Context - // init(&ctx) No-op - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream will read the stream in chunks and compute a -// hash from its contents -hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: Md2_Context - // init(&ctx) No-op - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file will read the file provided by the given handle -// and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false -} - -hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, -} - -/* - Low level API -*/ - -@(warning="Init is a no-op for MD2") -init :: proc(ctx: ^Md2_Context) { - // No action needed here -} - -update :: proc(ctx: ^Md2_Context, data: []byte) { - for i := 0; i < len(data); i += 1 { - ctx.data[ctx.datalen] = data[i] - ctx.datalen += 1 - if (ctx.datalen == DIGEST_SIZE) { - transform(ctx, ctx.data[:]) - ctx.datalen = 0 - } - } -} - -final :: proc(ctx: ^Md2_Context, hash: []byte) { - to_pad := byte(DIGEST_SIZE - ctx.datalen) - for ctx.datalen < DIGEST_SIZE { - ctx.data[ctx.datalen] = to_pad - ctx.datalen += 1 - } - transform(ctx, ctx.data[:]) - transform(ctx, ctx.checksum[:]) - for i := 0; i < DIGEST_SIZE; i += 1 { - hash[i] = ctx.state[i] - } -} - -/* - MD2 implementation -*/ - -Md2_Context :: struct { - data: [DIGEST_SIZE]byte, - state: [DIGEST_SIZE * 3]byte, - checksum: [DIGEST_SIZE]byte, - datalen: int, -} - -PI_TABLE := [?]byte { - 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, - 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, - 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, - 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, - 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, - 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, - 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, - 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, - 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, - 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, - 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221, - 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, - 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, - 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, - 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, - 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, - 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, - 20, -} - -transform :: proc(ctx: ^Md2_Context, data: []byte) { - j,k,t: byte - for j = 0; j < DIGEST_SIZE; j += 1 { - ctx.state[j + DIGEST_SIZE] = data[j] - ctx.state[j + DIGEST_SIZE * 2] = (ctx.state[j + DIGEST_SIZE] ~ ctx.state[j]) - } - t = 0 - for j = 0; j < DIGEST_SIZE + 2; j += 1 { - for k = 0; k < DIGEST_SIZE * 3; k += 1 { - ctx.state[k] ~= PI_TABLE[t] - t = ctx.state[k] - } - t = (t + j) & 0xff - } - t = ctx.checksum[DIGEST_SIZE - 1] - for j = 0; j < DIGEST_SIZE; j += 1 { - ctx.checksum[j] ~= PI_TABLE[data[j] ~ t] - t = ctx.checksum[j] - } -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 0b5cde5e9..7703c3477 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -28,7 +28,6 @@ import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" import chacha20poly1305 "core:crypto/chacha20poly1305" import keccak "core:crypto/keccak" -import md2 "core:crypto/md2" import md4 "core:crypto/md4" import md5 "core:crypto/md5" import poly1305 "core:crypto/poly1305" @@ -150,7 +149,6 @@ _ :: blake2s _ :: chacha20 _ :: chacha20poly1305 _ :: keccak -_ :: md2 _ :: md4 _ :: md5 _ :: poly1305 diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 979ca715f..b6825fc71 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -16,7 +16,6 @@ import "core:testing" import "core:fmt" import "core:strings" -import "core:crypto/md2" import "core:crypto/md4" import "core:crypto/md5" import "core:crypto/sha1" @@ -58,7 +57,6 @@ when ODIN_TEST { main :: proc() { t := testing.T{} - test_md2(&t) test_md4(&t) test_md5(&t) test_sha1(&t) @@ -125,25 +123,6 @@ hex_string :: proc(bytes: []byte, allocator := context.temp_allocator) -> string return string(buf) } -@(test) -test_md2 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 - test_vectors := [?]TestHash { - TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, - TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, - TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, - TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, - TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md2.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_md4 :: proc(t: ^testing.T) { // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 From 235fec23af7c90e4a81a6dcd89d8d069a7c9e0c7 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:46:20 +0900 Subject: [PATCH 095/160] core/crypto/md4: Remove, badly broken --- core/crypto/README.md | 1 - core/crypto/md4/md4.odin | 263 ---------------------- examples/all/all_main.odin | 2 - examples/all/all_vendor.odin | 2 - tests/core/crypto/test_core_crypto.odin | 21 -- tests/vendor/botan/test_vendor_botan.odin | 21 -- vendor/botan/README.md | 1 - vendor/botan/bindings/botan.odin | 1 - vendor/botan/md4/md4.odin | 121 ---------- 9 files changed, 433 deletions(-) delete mode 100644 core/crypto/md4/md4.odin delete mode 100644 vendor/botan/md4/md4.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index 28d7cc94b..973247f58 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -11,7 +11,6 @@ Please see the chart below for the options. | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | -| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | | [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | | [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | | [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | diff --git a/core/crypto/md4/md4.odin b/core/crypto/md4/md4.odin deleted file mode 100644 index 8efdbb5a5..000000000 --- a/core/crypto/md4/md4.odin +++ /dev/null @@ -1,263 +0,0 @@ -package md4 - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. - - Implementation of the MD4 hashing algorithm, as defined in RFC 1320 -*/ - -import "core:mem" -import "core:os" -import "core:io" - -import "../util" - -/* - High level API -*/ - -DIGEST_SIZE :: 16 - -// hash_string will hash the given input and return the -// computed hash -hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) -} - -// hash_bytes will hash the given input and return the -// computed hash -hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: Md4_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: Md4_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream will read the stream in chunks and compute a -// hash from its contents -hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: Md4_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file will read the file provided by the given handle -// and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false -} - -hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, -} - -/* - Low level API -*/ - -init :: proc(ctx: ^Md4_Context) { - ctx.state[0] = 0x67452301 - ctx.state[1] = 0xefcdab89 - ctx.state[2] = 0x98badcfe - ctx.state[3] = 0x10325476 -} - -update :: proc(ctx: ^Md4_Context, data: []byte) { - for i := 0; i < len(data); i += 1 { - ctx.data[ctx.datalen] = data[i] - ctx.datalen += 1 - if(ctx.datalen == BLOCK_SIZE) { - transform(ctx, ctx.data[:]) - ctx.bitlen += 512 - ctx.datalen = 0 - } - } -} - -final :: proc(ctx: ^Md4_Context, hash: []byte) { - i := ctx.datalen - if ctx.datalen < 56 { - ctx.data[i] = 0x80 - i += 1 - for i < 56 { - ctx.data[i] = 0x00 - i += 1 - } - } else if ctx.datalen >= 56 { - ctx.data[i] = 0x80 - i += 1 - for i < BLOCK_SIZE { - ctx.data[i] = 0x00 - i += 1 - } - transform(ctx, ctx.data[:]) - mem.set(&ctx.data, 0, 56) - } - - ctx.bitlen += u64(ctx.datalen * 8) - ctx.data[56] = byte(ctx.bitlen) - ctx.data[57] = byte(ctx.bitlen >> 8) - ctx.data[58] = byte(ctx.bitlen >> 16) - ctx.data[59] = byte(ctx.bitlen >> 24) - ctx.data[60] = byte(ctx.bitlen >> 32) - ctx.data[61] = byte(ctx.bitlen >> 40) - ctx.data[62] = byte(ctx.bitlen >> 48) - ctx.data[63] = byte(ctx.bitlen >> 56) - transform(ctx, ctx.data[:]) - - for i = 0; i < 4; i += 1 { - hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff - hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff - hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff - hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff - } -} - -/* - MD4 implementation -*/ - -BLOCK_SIZE :: 64 - -Md4_Context :: struct { - data: [64]byte, - state: [4]u32, - bitlen: u64, - datalen: u32, -} - -/* - @note(zh): F, G and H, as mentioned in the RFC, have been inlined into FF, GG - and HH respectively, instead of declaring them separately. -*/ - -FF :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 { - return util.ROTL32(a + ((b & c) | (~b & d)) + x, s) -} - -GG :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 { - return util.ROTL32(a + ((b & c) | (b & d) | (c & d)) + x + 0x5a827999, s) -} - -HH :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 { - return util.ROTL32(a + (b ~ c ~ d) + x + 0x6ed9eba1, s) -} - -transform :: proc(ctx: ^Md4_Context, data: []byte) { - a, b, c, d, i, j: u32 - m: [DIGEST_SIZE]u32 - - for i, j = 0, 0; i < DIGEST_SIZE; i += 1 { - m[i] = u32(data[j]) | (u32(data[j + 1]) << 8) | (u32(data[j + 2]) << 16) | (u32(data[j + 3]) << 24) - j += 4 - } - - a = ctx.state[0] - b = ctx.state[1] - c = ctx.state[2] - d = ctx.state[3] - - a = FF(a, b, c, d, m[0], 3) - d = FF(d, a, b, c, m[1], 7) - c = FF(c, d, a, b, m[2], 11) - b = FF(b, c, d, a, m[3], 19) - a = FF(a, b, c, d, m[4], 3) - d = FF(d, a, b, c, m[5], 7) - c = FF(c, d, a, b, m[6], 11) - b = FF(b, c, d, a, m[7], 19) - a = FF(a, b, c, d, m[8], 3) - d = FF(d, a, b, c, m[9], 7) - c = FF(c, d, a, b, m[10], 11) - b = FF(b, c, d, a, m[11], 19) - a = FF(a, b, c, d, m[12], 3) - d = FF(d, a, b, c, m[13], 7) - c = FF(c, d, a, b, m[14], 11) - b = FF(b, c, d, a, m[15], 19) - - a = GG(a, b, c, d, m[0], 3) - d = GG(d, a, b, c, m[4], 5) - c = GG(c, d, a, b, m[8], 9) - b = GG(b, c, d, a, m[12], 13) - a = GG(a, b, c, d, m[1], 3) - d = GG(d, a, b, c, m[5], 5) - c = GG(c, d, a, b, m[9], 9) - b = GG(b, c, d, a, m[13], 13) - a = GG(a, b, c, d, m[2], 3) - d = GG(d, a, b, c, m[6], 5) - c = GG(c, d, a, b, m[10], 9) - b = GG(b, c, d, a, m[14], 13) - a = GG(a, b, c, d, m[3], 3) - d = GG(d, a, b, c, m[7], 5) - c = GG(c, d, a, b, m[11], 9) - b = GG(b, c, d, a, m[15], 13) - - a = HH(a, b, c, d, m[0], 3) - d = HH(d, a, b, c, m[8], 9) - c = HH(c, d, a, b, m[4], 11) - b = HH(b, c, d, a, m[12], 15) - a = HH(a, b, c, d, m[2], 3) - d = HH(d, a, b, c, m[10], 9) - c = HH(c, d, a, b, m[6], 11) - b = HH(b, c, d, a, m[14], 15) - a = HH(a, b, c, d, m[1], 3) - d = HH(d, a, b, c, m[9], 9) - c = HH(c, d, a, b, m[5], 11) - b = HH(b, c, d, a, m[13], 15) - a = HH(a, b, c, d, m[3], 3) - d = HH(d, a, b, c, m[11], 9) - c = HH(c, d, a, b, m[7], 11) - b = HH(b, c, d, a, m[15], 15) - - ctx.state[0] += a - ctx.state[1] += b - ctx.state[2] += c - ctx.state[3] += d -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 7703c3477..4524ebf2a 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -28,7 +28,6 @@ import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" import chacha20poly1305 "core:crypto/chacha20poly1305" import keccak "core:crypto/keccak" -import md4 "core:crypto/md4" import md5 "core:crypto/md5" import poly1305 "core:crypto/poly1305" import ripemd "core:crypto/ripemd" @@ -149,7 +148,6 @@ _ :: blake2s _ :: chacha20 _ :: chacha20poly1305 _ :: keccak -_ :: md4 _ :: md5 _ :: poly1305 _ :: ripemd diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 0a13d74bd..8722aabe8 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -3,7 +3,6 @@ package all import botan_bindings "vendor:botan/bindings" import botan_blake2b "vendor:botan/blake2b" import keccak "vendor:botan/keccak" -import md4 "vendor:botan/md4" import md5 "vendor:botan/md5" import ripemd "vendor:botan/ripemd" import sha1 "vendor:botan/sha1" @@ -48,7 +47,6 @@ import fontstash "vendor:fontstash" _ :: botan_bindings _ :: botan_blake2b _ :: keccak -_ :: md4 _ :: md5 _ :: ripemd _ :: sha1 diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index b6825fc71..af45ef85a 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -16,7 +16,6 @@ import "core:testing" import "core:fmt" import "core:strings" -import "core:crypto/md4" import "core:crypto/md5" import "core:crypto/sha1" import "core:crypto/sha2" @@ -57,7 +56,6 @@ when ODIN_TEST { main :: proc() { t := testing.T{} - test_md4(&t) test_md5(&t) test_sha1(&t) test_sha224(&t) @@ -123,25 +121,6 @@ hex_string :: proc(bytes: []byte, allocator := context.temp_allocator) -> string return string(buf) } -@(test) -test_md4 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 - test_vectors := [?]TestHash { - TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, - TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, - TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, - TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, - TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md4.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_md5 :: proc(t: ^testing.T) { // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index eecfdd692..33f8b149a 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -17,7 +17,6 @@ import "core:fmt" import "core:os" import "core:strings" -import "vendor:botan/md4" import "vendor:botan/md5" import "vendor:botan/sha1" import "vendor:botan/sha2" @@ -58,7 +57,6 @@ when ODIN_TEST { main :: proc() { t := testing.T{} - test_md4(&t) test_md5(&t) test_sha1(&t) test_sha224(&t) @@ -106,25 +104,6 @@ hex_string :: proc(bytes: []byte, allocator := context.temp_allocator) -> string return string(buf) } -@(test) -test_md4 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 - test_vectors := [?]TestHash { - TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, - TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, - TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, - TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, - TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md4.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_md5 :: proc(t: ^testing.T) { // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 diff --git a/vendor/botan/README.md b/vendor/botan/README.md index 539e2f820..d618d727c 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -10,7 +10,6 @@ Wrappers for hashing algorithms have been added to match the API within the Odin |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | -| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | | [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | | [RIPEMD-160](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | | [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 0a36dbdd9..57fa78a37 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -77,7 +77,6 @@ HASH_KECCAK_512 :: "Keccak-1600" HASH_RIPEMD_160 :: "RIPEMD-160" HASH_WHIRLPOOL :: "Whirlpool" HASH_BLAKE2B :: "BLAKE2b" -HASH_MD4 :: "MD4" HASH_MD5 :: "MD5" HASH_TIGER_128 :: "Tiger(16,3)" HASH_TIGER_160 :: "Tiger(20,3)" diff --git a/vendor/botan/md4/md4.odin b/vendor/botan/md4/md4.odin deleted file mode 100644 index 02c33dde9..000000000 --- a/vendor/botan/md4/md4.odin +++ /dev/null @@ -1,121 +0,0 @@ -package vendor_md4 - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial implementation. - - Interface for the MD4 hashing algorithm. - The hash will be computed via bindings to the Botan crypto library -*/ - -import "core:os" -import "core:io" - -import botan "../bindings" - -/* - High level API -*/ - -DIGEST_SIZE :: 16 - -// hash_string will hash the given input and return the -// computed hash -hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) -} - -// hash_bytes will hash the given input and return the -// computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_MD4, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_MD4, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream will read the stream in chunks and compute a -// hash from its contents -hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_MD4, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file will read the file provided by the given handle -// and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false -} - -hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, -} - -/* - Low level API -*/ - -Md4_Context :: botan.hash_t - -init :: proc "contextless" (ctx: ^botan.hash_t) { - botan.hash_init(ctx, botan.HASH_MD4, 0) -} - -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { - botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) -} - -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { - botan.hash_final(ctx^, &hash[0]) - botan.hash_destroy(ctx^) -} From 3494a6dcd8249c2e705ed81f42ddfc03c9c23a78 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:50:30 +0900 Subject: [PATCH 096/160] core/crypto/ripemd: Remove, historical/exotic --- core/crypto/README.md | 1 - core/crypto/ripemd/ripemd.odin | 919 ---------------------- examples/all/all_main.odin | 2 - examples/all/all_vendor.odin | 2 - tests/core/crypto/test_core_crypto.odin | 85 -- tests/vendor/botan/test_vendor_botan.odin | 22 - vendor/botan/README.md | 1 - vendor/botan/bindings/botan.odin | 1 - vendor/botan/ripemd/ripemd.odin | 121 --- 9 files changed, 1154 deletions(-) delete mode 100644 core/crypto/ripemd/ripemd.odin delete mode 100644 vendor/botan/ripemd/ripemd.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index 973247f58..82db2775f 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -12,7 +12,6 @@ Please see the chart below for the options. | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | -| [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | | [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | | [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | diff --git a/core/crypto/ripemd/ripemd.odin b/core/crypto/ripemd/ripemd.odin deleted file mode 100644 index f9edb121b..000000000 --- a/core/crypto/ripemd/ripemd.odin +++ /dev/null @@ -1,919 +0,0 @@ -package ripemd - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation for the RIPEMD hashing algorithm as defined in -*/ - -import "core:os" -import "core:io" - -import "../util" - -/* - High level API -*/ - -DIGEST_SIZE_128 :: 16 -DIGEST_SIZE_160 :: 20 -DIGEST_SIZE_256 :: 32 -DIGEST_SIZE_320 :: 40 - -// hash_string_128 will hash the given input and return the -// computed hash -hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128(transmute([]byte)(data)) -} - -// hash_bytes_128 will hash the given input and return the -// computed hash -hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: Ripemd128_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_128 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_128 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: Ripemd128_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_128 will read the stream in chunks and compute a -// hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: Ripemd128_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_128 will read the file provided by the given handle -// and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false -} - -hash_128 :: proc { - hash_stream_128, - hash_file_128, - hash_bytes_128, - hash_string_128, - hash_bytes_to_buffer_128, - hash_string_to_buffer_128, -} - -// hash_string_160 will hash the given input and return the -// computed hash -hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160(transmute([]byte)(data)) -} - -// hash_bytes_160 will hash the given input and return the -// computed hash -hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: Ripemd160_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_160 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: Ripemd160_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_160 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: Ripemd160_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_160 will read the file provided by the given handle -// and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160 :: proc { - hash_stream_160, - hash_file_160, - hash_bytes_160, - hash_string_160, - hash_bytes_to_buffer_160, - hash_string_to_buffer_160, -} - -// hash_string_256 will hash the given input and return the -// computed hash -hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) -} - -// hash_bytes_256 will hash the given input and return the -// computed hash -hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Ripemd256_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Ripemd256_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_256 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Ripemd256_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256 will read the file provided by the given handle -// and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, -} - -// hash_string_320 will hash the given input and return the -// computed hash -hash_string_320 :: proc(data: string) -> [DIGEST_SIZE_320]byte { - return hash_bytes_320(transmute([]byte)(data)) -} - -// hash_bytes_320 will hash the given input and return the -// computed hash -hash_bytes_320 :: proc(data: []byte) -> [DIGEST_SIZE_320]byte { - hash: [DIGEST_SIZE_320]byte - ctx: Ripemd320_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_320 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_320 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_320(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_320 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_320 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_320, "Size of destination buffer is smaller than the digest size") - ctx: Ripemd320_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream_320 will read the stream in chunks and compute a -// hash from its contents -hash_stream_320 :: proc(s: io.Stream) -> ([DIGEST_SIZE_320]byte, bool) { - hash: [DIGEST_SIZE_320]byte - ctx: Ripemd320_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_320 will read the file provided by the given handle -// and compute a hash -hash_file_320 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_320]byte, bool) { - if !load_at_once { - return hash_stream_320(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_320(buf[:]), ok - } - } - return [DIGEST_SIZE_320]byte{}, false -} - -hash_320 :: proc { - hash_stream_320, - hash_file_320, - hash_bytes_320, - hash_string_320, - hash_bytes_to_buffer_320, - hash_string_to_buffer_320, -} - -/* - Low level API -*/ - -init :: proc(ctx: ^$T) { - when T == Ripemd128_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 - } else when T == Ripemd160_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 - } else when T == Ripemd256_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 - ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7] = S5, S6, S7, S8 - } else when T == Ripemd320_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 - ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9] = S5, S6, S7, S8, S9 - } -} - -update :: proc(ctx: ^$T, data: []byte) { - ctx.tc += u64(len(data)) - data := data - if ctx.nx > 0 { - n := len(data) - - when T == Ripemd128_Context { - if n > RIPEMD_128_BLOCK_SIZE - ctx.nx { - n = RIPEMD_128_BLOCK_SIZE - ctx.nx - } - } else when T == Ripemd160_Context { - if n > RIPEMD_160_BLOCK_SIZE - ctx.nx { - n = RIPEMD_160_BLOCK_SIZE - ctx.nx - } - } else when T == Ripemd256_Context{ - if n > RIPEMD_256_BLOCK_SIZE - ctx.nx { - n = RIPEMD_256_BLOCK_SIZE - ctx.nx - } - } else when T == Ripemd320_Context{ - if n > RIPEMD_320_BLOCK_SIZE - ctx.nx { - n = RIPEMD_320_BLOCK_SIZE - ctx.nx - } - } - - for i := 0; i < n; i += 1 { - ctx.x[ctx.nx + i] = data[i] - } - - ctx.nx += n - when T == Ripemd128_Context { - if ctx.nx == RIPEMD_128_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } else when T == Ripemd160_Context { - if ctx.nx == RIPEMD_160_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } else when T == Ripemd256_Context{ - if ctx.nx == RIPEMD_256_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } else when T == Ripemd320_Context{ - if ctx.nx == RIPEMD_320_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } - data = data[n:] - } - n := block(ctx, data) - data = data[n:] - if len(data) > 0 { - ctx.nx = copy(ctx.x[:], data) - } -} - -final :: proc(ctx: ^$T, hash: []byte) { - d := ctx - tc := d.tc - tmp: [64]byte - tmp[0] = 0x80 - - if tc % 64 < 56 { - update(d, tmp[0:56 - tc % 64]) - } else { - update(d, tmp[0:64 + 56 - tc % 64]) - } - - tc <<= 3 - for i : u32 = 0; i < 8; i += 1 { - tmp[i] = byte(tc >> (8 * i)) - } - - update(d, tmp[0:8]) - - when T == Ripemd128_Context { - size :: RIPEMD_128_SIZE - } else when T == Ripemd160_Context { - size :: RIPEMD_160_SIZE - } else when T == Ripemd256_Context{ - size :: RIPEMD_256_SIZE - } else when T == Ripemd320_Context{ - size :: RIPEMD_320_SIZE - } - - digest: [size]byte - for s, i in d.s { - digest[i * 4] = byte(s) - digest[i * 4 + 1] = byte(s >> 8) - digest[i * 4 + 2] = byte(s >> 16) - digest[i * 4 + 3] = byte(s >> 24) - } - copy(hash[:], digest[:]) -} - - -/* - RIPEMD implementation -*/ - -Ripemd128_Context :: struct { - s: [4]u32, - x: [RIPEMD_128_BLOCK_SIZE]byte, - nx: int, - tc: u64, -} - -Ripemd160_Context :: struct { - s: [5]u32, - x: [RIPEMD_160_BLOCK_SIZE]byte, - nx: int, - tc: u64, -} - -Ripemd256_Context :: struct { - s: [8]u32, - x: [RIPEMD_256_BLOCK_SIZE]byte, - nx: int, - tc: u64, -} - -Ripemd320_Context :: struct { - s: [10]u32, - x: [RIPEMD_320_BLOCK_SIZE]byte, - nx: int, - tc: u64, -} - -RIPEMD_128_SIZE :: 16 -RIPEMD_128_BLOCK_SIZE :: 64 -RIPEMD_160_SIZE :: 20 -RIPEMD_160_BLOCK_SIZE :: 64 -RIPEMD_256_SIZE :: 32 -RIPEMD_256_BLOCK_SIZE :: 64 -RIPEMD_320_SIZE :: 40 -RIPEMD_320_BLOCK_SIZE :: 64 - -S0 :: 0x67452301 -S1 :: 0xefcdab89 -S2 :: 0x98badcfe -S3 :: 0x10325476 -S4 :: 0xc3d2e1f0 -S5 :: 0x76543210 -S6 :: 0xfedcba98 -S7 :: 0x89abcdef -S8 :: 0x01234567 -S9 :: 0x3c2d1e0f - -RIPEMD_128_N0 := [64]uint { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, - 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, - 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, -} - -RIPEMD_128_R0 := [64]uint { - 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, - 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, - 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, - 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, -} - -RIPEMD_128_N1 := [64]uint { - 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, - 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, - 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, - 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, -} - -RIPEMD_128_R1 := [64]uint { - 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, - 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, - 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, - 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, -} - -RIPEMD_160_N0 := [80]uint { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, - 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, - 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, - 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13, -} - -RIPEMD_160_R0 := [80]uint { - 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, - 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, - 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, - 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, - 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6, -} - -RIPEMD_160_N1 := [80]uint { - 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, - 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, - 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, - 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, - 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11, -} - -RIPEMD_160_R1 := [80]uint { - 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, - 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, - 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, - 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, - 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11, -} - -block :: #force_inline proc (ctx: ^$T, p: []byte) -> int { - when T == Ripemd128_Context { - return ripemd_128_block(ctx, p) - } - else when T == Ripemd160_Context { - return ripemd_160_block(ctx, p) - } - else when T == Ripemd256_Context { - return ripemd_256_block(ctx, p) - } - else when T == Ripemd320_Context { - return ripemd_320_block(ctx, p) - } -} - -ripemd_128_block :: proc(ctx: ^$T, p: []byte) -> int { - n := 0 - x: [16]u32 = --- - alpha: u32 = --- - p := p - for len(p) >= RIPEMD_128_BLOCK_SIZE { - a, b, c, d := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] - aa, bb, cc, dd := a, b, c, d - for i,j := 0, 0; i < 16; i, j = i+1, j+4 { - x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 - } - i := 0 - for i < 16 { - alpha = a + (b ~ c ~ d) + x[RIPEMD_128_N0[i]] - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (bb & dd | cc &~ dd) + x[RIPEMD_128_N1[i]] + 0x50a28be6 - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd= dd, alpha, bb, cc - i += 1 - } - for i < 32 { - alpha = a + (d ~ (b & (c~d))) + x[RIPEMD_128_N0[i]] + 0x5a827999 - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (dd ~ (bb | ~cc)) + x[RIPEMD_128_N1[i]] + 0x5c4dd124 - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd = dd, alpha, bb, cc - i += 1 - } - for i < 48 { - alpha = a + (d ~ (b | ~c)) + x[RIPEMD_128_N0[i]] + 0x6ed9eba1 - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (dd ~ (bb & (cc~dd))) + x[RIPEMD_128_N1[i]] + 0x6d703ef3 - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd = dd, alpha, bb, cc - i += 1 - } - for i < 64 { - alpha = a + (c ~ (d & (b~c))) + x[RIPEMD_128_N0[i]] + 0x8f1bbcdc - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_128_N1[i]] - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd = dd, alpha, bb, cc - i += 1 - } - c = ctx.s[1] + c + dd - ctx.s[1] = ctx.s[2] + d + aa - ctx.s[2] = ctx.s[3] + a + bb - ctx.s[3] = ctx.s[0] + b + cc - ctx.s[0] = c - p = p[RIPEMD_128_BLOCK_SIZE:] - n += RIPEMD_128_BLOCK_SIZE - } - return n -} - -ripemd_160_block :: proc(ctx: ^$T, p: []byte) -> int { - n := 0 - x: [16]u32 = --- - alpha, beta: u32 = ---, --- - p := p - for len(p) >= RIPEMD_160_BLOCK_SIZE { - a, b, c, d, e := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] - aa, bb, cc, dd, ee := a, b, c, d, e - for i,j := 0, 0; i < 16; i, j = i+1, j+4 { - x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 - } - i := 0 - for i < 16 { - alpha = a + (b ~ c ~ d) + x[RIPEMD_160_N0[i]] - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb ~ (cc | ~dd)) + x[RIPEMD_160_N1[i]] + 0x50a28be6 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - for i < 32 { - alpha = a + (b&c | ~b&d) + x[RIPEMD_160_N0[i]] + 0x5a827999 - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb&dd | cc&~dd) + x[RIPEMD_160_N1[i]] + 0x5c4dd124 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - for i < 48 { - alpha = a + (b | ~c ~ d) + x[RIPEMD_160_N0[i]] + 0x6ed9eba1 - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb | ~cc ~ dd) + x[RIPEMD_160_N1[i]] + 0x6d703ef3 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - for i < 64 { - alpha = a + (b&d | c&~d) + x[RIPEMD_160_N0[i]] + 0x8f1bbcdc - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb&cc | ~bb&dd) + x[RIPEMD_160_N1[i]] + 0x7a6d76e9 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - for i < 80 { - alpha = a + (b ~ (c | ~d)) + x[RIPEMD_160_N0[i]] + 0xa953fd4e - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_160_N1[i]] - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - dd += c + ctx.s[1] - ctx.s[1] = ctx.s[2] + d + ee - ctx.s[2] = ctx.s[3] + e + aa - ctx.s[3] = ctx.s[4] + a + bb - ctx.s[4] = ctx.s[0] + b + cc - ctx.s[0] = dd - p = p[RIPEMD_160_BLOCK_SIZE:] - n += RIPEMD_160_BLOCK_SIZE - } - return n -} - -ripemd_256_block :: proc(ctx: ^$T, p: []byte) -> int { - n := 0 - x: [16]u32 = --- - alpha: u32 = --- - p := p - for len(p) >= RIPEMD_256_BLOCK_SIZE { - a, b, c, d := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] - aa, bb, cc, dd := ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7] - for i,j := 0, 0; i < 16; i, j = i+1, j+4 { - x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 - } - i := 0 - for i < 16 { - alpha = a + (b ~ c ~ d) + x[RIPEMD_128_N0[i]] - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (bb & dd | cc &~ dd) + x[RIPEMD_128_N1[i]] + 0x50a28be6 - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd= dd, alpha, bb, cc - i += 1 - } - t := a - a = aa - aa = t - for i < 32 { - alpha = a + (d ~ (b & (c~d))) + x[RIPEMD_128_N0[i]] + 0x5a827999 - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (dd ~ (bb | ~cc)) + x[RIPEMD_128_N1[i]] + 0x5c4dd124 - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd = dd, alpha, bb, cc - i += 1 - } - t = b - b = bb - bb = t - for i < 48 { - alpha = a + (d ~ (b | ~c)) + x[RIPEMD_128_N0[i]] + 0x6ed9eba1 - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (dd ~ (bb & (cc~dd))) + x[RIPEMD_128_N1[i]] + 0x6d703ef3 - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd = dd, alpha, bb, cc - i += 1 - } - t = c - c = cc - cc = t - for i < 64 { - alpha = a + (c ~ (d & (b~c))) + x[RIPEMD_128_N0[i]] + 0x8f1bbcdc - s := int(RIPEMD_128_R0[i]) - alpha = util.ROTL32(alpha, s) - a, b, c, d = d, alpha, b, c - alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_128_N1[i]] - s = int(RIPEMD_128_R1[i]) - alpha = util.ROTL32(alpha, s) - aa, bb, cc, dd = dd, alpha, bb, cc - i += 1 - } - t = d - d = dd - dd = t - ctx.s[0] += a - ctx.s[1] += b - ctx.s[2] += c - ctx.s[3] += d - ctx.s[4] += aa - ctx.s[5] += bb - ctx.s[6] += cc - ctx.s[7] += dd - p = p[RIPEMD_256_BLOCK_SIZE:] - n += RIPEMD_256_BLOCK_SIZE - } - return n -} - -ripemd_320_block :: proc(ctx: ^$T, p: []byte) -> int { - n := 0 - x: [16]u32 = --- - alpha, beta: u32 = ---, --- - p := p - for len(p) >= RIPEMD_320_BLOCK_SIZE { - a, b, c, d, e := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] - aa, bb, cc, dd, ee := ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9] - for i,j := 0, 0; i < 16; i, j = i+1, j+4 { - x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 - } - i := 0 - for i < 16 { - alpha = a + (b ~ c ~ d) + x[RIPEMD_160_N0[i]] - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb ~ (cc | ~dd)) + x[RIPEMD_160_N1[i]] + 0x50a28be6 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - t := b - b = bb - bb = t - for i < 32 { - alpha = a + (b&c | ~b&d) + x[RIPEMD_160_N0[i]] + 0x5a827999 - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb&dd | cc&~dd) + x[RIPEMD_160_N1[i]] + 0x5c4dd124 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - t = d - d = dd - dd = t - for i < 48 { - alpha = a + (b | ~c ~ d) + x[RIPEMD_160_N0[i]] + 0x6ed9eba1 - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb | ~cc ~ dd) + x[RIPEMD_160_N1[i]] + 0x6d703ef3 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - t = a - a = aa - aa = t - for i < 64 { - alpha = a + (b&d | c&~d) + x[RIPEMD_160_N0[i]] + 0x8f1bbcdc - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb&cc | ~bb&dd) + x[RIPEMD_160_N1[i]] + 0x7a6d76e9 - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - t = c - c = cc - cc = t - for i < 80 { - alpha = a + (b ~ (c | ~d)) + x[RIPEMD_160_N0[i]] + 0xa953fd4e - s := int(RIPEMD_160_R0[i]) - alpha = util.ROTL32(alpha, s) + e - beta = util.ROTL32(c, 10) - a, b, c, d, e = e, alpha, b, beta, d - alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_160_N1[i]] - s = int(RIPEMD_160_R1[i]) - alpha = util.ROTL32(alpha, s) + ee - beta = util.ROTL32(cc, 10) - aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd - i += 1 - } - t = e - e = ee - ee = t - ctx.s[0] += a - ctx.s[1] += b - ctx.s[2] += c - ctx.s[3] += d - ctx.s[4] += e - ctx.s[5] += aa - ctx.s[6] += bb - ctx.s[7] += cc - ctx.s[8] += dd - ctx.s[9] += ee - p = p[RIPEMD_320_BLOCK_SIZE:] - n += RIPEMD_320_BLOCK_SIZE - } - return n -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 4524ebf2a..74ac7401e 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -30,7 +30,6 @@ import chacha20poly1305 "core:crypto/chacha20poly1305" import keccak "core:crypto/keccak" import md5 "core:crypto/md5" import poly1305 "core:crypto/poly1305" -import ripemd "core:crypto/ripemd" import sha1 "core:crypto/sha1" import sha2 "core:crypto/sha2" import sha3 "core:crypto/sha3" @@ -150,7 +149,6 @@ _ :: chacha20poly1305 _ :: keccak _ :: md5 _ :: poly1305 -_ :: ripemd _ :: sha1 _ :: sha2 _ :: sha3 diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 8722aabe8..637cdfcb8 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -4,7 +4,6 @@ import botan_bindings "vendor:botan/bindings" import botan_blake2b "vendor:botan/blake2b" import keccak "vendor:botan/keccak" import md5 "vendor:botan/md5" -import ripemd "vendor:botan/ripemd" import sha1 "vendor:botan/sha1" import sha2 "vendor:botan/sha2" import sha3 "vendor:botan/sha3" @@ -48,7 +47,6 @@ _ :: botan_bindings _ :: botan_blake2b _ :: keccak _ :: md5 -_ :: ripemd _ :: sha1 _ :: sha2 _ :: sha3 diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index af45ef85a..362d79d2b 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -23,7 +23,6 @@ import "core:crypto/sha3" import "core:crypto/keccak" import "core:crypto/shake" import "core:crypto/whirlpool" -import "core:crypto/ripemd" import "core:crypto/blake2b" import "core:crypto/blake2s" import "core:crypto/tiger" @@ -78,10 +77,6 @@ main :: proc() { test_streebog_512(&t) test_blake2b(&t) test_blake2s(&t) - test_ripemd_128(&t) - test_ripemd_160(&t) - test_ripemd_256(&t) - test_ripemd_320(&t) test_tiger_128(&t) test_tiger_160(&t) test_tiger_192(&t) @@ -512,86 +507,6 @@ test_blake2s :: proc(t: ^testing.T) { } } -@(test) -test_ripemd_128 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, - TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, - TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, - TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, - TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_ripemd_160 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, - TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, - TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, - TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, - TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_ripemd_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, - TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, - TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, - TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, - TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_ripemd_320 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, - TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, - TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, - TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, - TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_320(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_tiger_128 :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 33f8b149a..05a2eb8e7 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -24,7 +24,6 @@ import "vendor:botan/sha3" import "vendor:botan/keccak" import "vendor:botan/shake" import "vendor:botan/whirlpool" -import "vendor:botan/ripemd" import "vendor:botan/blake2b" import "vendor:botan/tiger" import "vendor:botan/streebog" @@ -74,7 +73,6 @@ main :: proc() { test_streebog_256(&t) test_streebog_512(&t) test_blake2b(&t) - test_ripemd_160(&t) // test_tiger_128(&t) // test_tiger_160(&t) // test_tiger_192(&t) @@ -419,26 +417,6 @@ test_blake2b :: proc(t: ^testing.T) { } } -@(test) -test_ripemd_160 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, - TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, - TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, - TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, - TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_tiger_128 :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/vendor/botan/README.md b/vendor/botan/README.md index d618d727c..81f638dab 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -11,7 +11,6 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | -| [RIPEMD-160](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | | [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | | [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 57fa78a37..42add09de 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -74,7 +74,6 @@ HASH_SHA3_512 :: "SHA-3(512)" HASH_SHAKE_128 :: "SHAKE-128" HASH_SHAKE_256 :: "SHAKE-256" HASH_KECCAK_512 :: "Keccak-1600" -HASH_RIPEMD_160 :: "RIPEMD-160" HASH_WHIRLPOOL :: "Whirlpool" HASH_BLAKE2B :: "BLAKE2b" HASH_MD5 :: "MD5" diff --git a/vendor/botan/ripemd/ripemd.odin b/vendor/botan/ripemd/ripemd.odin deleted file mode 100644 index ddb549350..000000000 --- a/vendor/botan/ripemd/ripemd.odin +++ /dev/null @@ -1,121 +0,0 @@ -package vendor_ripemd - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Interface for the RIPEMD-160 hashing algorithm. - The hash will be computed via bindings to the Botan crypto library -*/ - -import "core:os" -import "core:io" - -import botan "../bindings" - -/* - High level API -*/ - -DIGEST_SIZE_160 :: 20 - -// hash_string_160 will hash the given input and return the -// computed hash -hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160(transmute([]byte)(data)) -} - -// hash_bytes_160 will hash the given input and return the -// computed hash -hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_RIPEMD_160, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_160 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_RIPEMD_160, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_160 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_RIPEMD_160, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_160 will read the file provided by the given handle -// and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160 :: proc { - hash_stream_160, - hash_file_160, - hash_bytes_160, - hash_string_160, - hash_bytes_to_buffer_160, - hash_string_to_buffer_160, -} - -/* - Low level API -*/ - -Ripemd160_Context :: botan.hash_t - -init :: proc "contextless" (ctx: ^botan.hash_t) { - botan.hash_init(ctx, botan.HASH_RIPEMD_160, 0) -} - -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { - botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) -} - -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { - botan.hash_final(ctx^, &hash[0]) - botan.hash_destroy(ctx^) -} From 32b27c690d0b2864a86786e9a115e21ab2bbb25f Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 17:37:27 +0900 Subject: [PATCH 097/160] vendor/botan/skein512: Remove, use SHA-3 --- examples/all/all_vendor.odin | 2 - tests/vendor/botan/test_vendor_botan.odin | 31 --- vendor/botan/README.md | 1 - vendor/botan/bindings/botan.odin | 5 - vendor/botan/skein512/skein512.odin | 286 ---------------------- 5 files changed, 325 deletions(-) delete mode 100644 vendor/botan/skein512/skein512.odin diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 637cdfcb8..432059f6a 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -9,7 +9,6 @@ import sha2 "vendor:botan/sha2" import sha3 "vendor:botan/sha3" import shake "vendor:botan/shake" import siphash "vendor:botan/siphash" -import skein512 "vendor:botan/skein512" import sm3 "vendor:botan/sm3" import streebog "vendor:botan/streebog" import tiger "vendor:botan/tiger" @@ -52,7 +51,6 @@ _ :: sha2 _ :: sha3 _ :: shake _ :: siphash -_ :: skein512 _ :: sm3 _ :: streebog _ :: tiger diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 05a2eb8e7..99d4e5c3f 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -28,7 +28,6 @@ import "vendor:botan/blake2b" import "vendor:botan/tiger" import "vendor:botan/streebog" import "vendor:botan/sm3" -import "vendor:botan/skein512" import "vendor:botan/siphash" TEST_count := 0 @@ -77,8 +76,6 @@ main :: proc() { // test_tiger_160(&t) // test_tiger_192(&t) test_sm3(&t) - test_skein512_256(&t) - test_skein512_512(&t) test_siphash_2_4(&t) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) @@ -493,34 +490,6 @@ test_sm3 :: proc(t: ^testing.T) { } } -@(test) -test_skein512_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"39ccc4554a8b31853b9de7a1fe638a24cce6b35a55f2431009e18780335d2621", ""}, - TestHash{"b3250457e05d3060b1a4bbc1428bc75a3f525ca389aeab96cfa34638d96e492a", "The quick brown fox jumps over the lazy dog"}, - TestHash{"41e829d7fca71c7d7154ed8fc8a069f274dd664ae0ed29d365d919f4e575eebb", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := skein512.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_skein512_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af41fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a", ""}, - TestHash{"94c2ae036dba8783d0b3f7d6cc111ff810702f5c77707999be7e1c9486ff238a7044de734293147359b4ac7e1d09cd247c351d69826b78dcddd951f0ef912713", "The quick brown fox jumps over the lazy dog"}, - TestHash{"658223cb3d69b5e76e3588ca63feffba0dc2ead38a95d0650564f2a39da8e83fbb42c9d6ad9e03fbfde8a25a880357d457dbd6f74cbcb5e728979577dbce5436", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := skein512.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_siphash_2_4 :: proc(t: ^testing.T) { // Test vectors from diff --git a/vendor/botan/README.md b/vendor/botan/README.md index 81f638dab..6d1087cbf 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -15,7 +15,6 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | -| [Skein-512](https://www.schneier.com/academic/skein/) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | | [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ | | [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 42add09de..7f3dc99b9 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -83,11 +83,6 @@ HASH_TIGER_192 :: "Tiger(24,3)" HASH_STREEBOG_256 :: "Streebog-256" HASH_STREEBOG_512 :: "Streebog-512" HASH_SM3 :: "SM3" -HASH_SKEIN_512_256 :: "Skein-512(256)" -HASH_SKEIN_512_512 :: "Skein-512(512)" - -// Not real values from Botan, only used for context setup within the crypto lib -HASH_SKEIN_512 :: "SKEIN_512" MAC_HMAC_SHA1 :: "HMAC(SHA1)" MAC_HMAC_SHA_224 :: "HMAC(SHA-224)" diff --git a/vendor/botan/skein512/skein512.odin b/vendor/botan/skein512/skein512.odin deleted file mode 100644 index 47529bc44..000000000 --- a/vendor/botan/skein512/skein512.odin +++ /dev/null @@ -1,286 +0,0 @@ -package vendor_skein512 - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Interface for the SKEIN-512 hashing algorithm. - The hash will be computed via bindings to the Botan crypto library -*/ - -import "core:os" -import "core:io" -import "core:strings" -import "core:fmt" - -import botan "../bindings" - -/* - High level API -*/ - -DIGEST_SIZE_256 :: 32 -DIGEST_SIZE_512 :: 64 - -// hash_string_256 will hash the given input and return the -// computed hash -hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) -} - -// hash_bytes_256 will hash the given input and return the -// computed hash -hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SKEIN_512_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_256 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SKEIN_512_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_256 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SKEIN_512_256, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_256 will read the file provided by the given handle -// and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, -} - -// hash_string_512 will hash the given input and return the -// computed hash -hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) -} - -// hash_bytes_512 will hash the given input and return the -// computed hash -hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SKEIN_512_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_512 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_512 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SKEIN_512_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_512 will read the stream in chunks and compute a -// hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SKEIN_512_512, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_512 will read the file provided by the given handle -// and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false -} - -hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, -} - -// hash_string_slice will hash the given input and return the -// computed hash -hash_string_slice :: proc(data: string, bit_size: int, allocator := context.allocator) -> []byte { - return hash_bytes_slice(transmute([]byte)(data), bit_size, allocator) -} - -// hash_bytes_slice will hash the given input and return the -// computed hash -hash_bytes_slice :: proc(data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - hash := make([]byte, bit_size, allocator) - ctx: botan.hash_t - botan.hash_init(&ctx, strings.unsafe_string_to_cstring(fmt.tprintf("Skein-512(%d)", bit_size * 8)), 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_512 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_slice :: proc(data: string, hash: []byte, bit_size: int, allocator := context.allocator) { - hash_bytes_to_buffer_slice(transmute([]byte)(data), hash, bit_size, allocator) -} - -// hash_bytes_to_buffer_slice will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_slice :: proc(data, hash: []byte, bit_size: int, allocator := context.allocator) { - assert(len(hash) >= bit_size, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, strings.unsafe_string_to_cstring(fmt.tprintf("Skein-512(%d)", bit_size * 8)), 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_slice will read the stream in chunks and compute a -// hash from its contents -hash_stream_slice :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - hash := make([]byte, bit_size, allocator) - ctx: botan.hash_t - botan.hash_init(&ctx, strings.unsafe_string_to_cstring(fmt.tprintf("Skein-512(%d)", bit_size * 8)), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_slice will read the file provided by the given handle -// and compute a hash -hash_file_slice :: proc(hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - if !load_at_once { - return hash_stream_slice(os.stream_from_handle(hd), bit_size, allocator) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_slice(buf[:], bit_size, allocator), ok - } - } - return nil, false -} - -hash_slice :: proc { - hash_stream_slice, - hash_file_slice, - hash_bytes_slice, - hash_string_slice, - hash_bytes_to_buffer_slice, - hash_string_to_buffer_slice, -} - -/* - Low level API -*/ - -Skein512_Context :: botan.hash_t - -init :: proc(ctx: ^botan.hash_t, hash_size := 512) { - switch hash_size { - case 256: botan.hash_init(ctx, botan.HASH_SKEIN_512_256, 0) - case 512: botan.hash_init(ctx, botan.HASH_SKEIN_512_512, 0) - case: botan.hash_init(ctx, strings.unsafe_string_to_cstring(fmt.tprintf("Skein-512(%d)", hash_size)), 0) - } -} - -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { - botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) -} - -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { - botan.hash_final(ctx^, &hash[0]) - botan.hash_destroy(ctx^) -} From 8d943f590218beb970b4ef3f9b6caf7a8a852c18 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:53:42 +0900 Subject: [PATCH 098/160] core/crypto/streebog: Remove, exotic --- core/crypto/README.md | 1 - core/crypto/streebog/streebog.odin | 517 ---------------------- examples/all/all_main.odin | 2 - examples/all/all_vendor.odin | 2 - tests/core/crypto/test_core_crypto.odin | 31 -- tests/vendor/botan/test_vendor_botan.odin | 31 -- vendor/botan/README.md | 1 - vendor/botan/bindings/botan.odin | 2 - vendor/botan/streebog/streebog.odin | 204 --------- 9 files changed, 791 deletions(-) delete mode 100644 core/crypto/streebog/streebog.odin delete mode 100644 vendor/botan/streebog/streebog.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index 82db2775f..eaf8c13e2 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -17,7 +17,6 @@ Please see the chart below for the options. | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | -| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ | | [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | | [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | | [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | diff --git a/core/crypto/streebog/streebog.odin b/core/crypto/streebog/streebog.odin deleted file mode 100644 index 42da1e695..000000000 --- a/core/crypto/streebog/streebog.odin +++ /dev/null @@ -1,517 +0,0 @@ -package streebog - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the Streebog hashing algorithm, standardized as GOST R 34.11-2012 in RFC 6986 -*/ - -import "core:os" -import "core:io" - -import "../util" - -/* - High level API -*/ - -DIGEST_SIZE_256 :: 32 -DIGEST_SIZE_512 :: 64 - -// hash_string_256 will hash the given input and return the -// computed hash -hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) -} - -// hash_bytes_256 will hash the given input and return the -// computed hash -hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: Streebog_Context - ctx.is256 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_256 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: Streebog_Context - ctx.is256 = true - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) -} - -// hash_stream_256 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: Streebog_Context - ctx.is256 = true - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_256 will read the file provided by the given handle -// and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, -} - -// hash_string_512 will hash the given input and return the -// computed hash -hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) -} - -// hash_bytes_512 will hash the given input and return the -// computed hash -hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: Streebog_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_512 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_512 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: Streebog_Context - init(&ctx) - update(&ctx, data) - final(&ctx, hash[:]) -} - -// hash_stream_512 will read the stream in chunks and compute a -// hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: Streebog_Context - init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file_512 will read the file provided by the given handle -// and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false -} - -hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, -} - -/* - Low level API -*/ - -init :: proc(ctx: ^Streebog_Context) { - if ctx.is256 { - ctx.hash_size = 256 - for _, i in ctx.h { - ctx.h[i] = 0x01 - } - } else { - ctx.hash_size = 512 - } - ctx.v_512[1] = 0x02 -} - -update :: proc(ctx: ^Streebog_Context, data: []byte) { - length := u64(len(data)) - chk_size: u64 - data := data - for (length > 63) && (ctx.buf_size == 0) { - stage2(ctx, data) - data = data[64:] - length -= 64 - } - - for length != 0 { - chk_size = 64 - ctx.buf_size - if chk_size > length { - chk_size = length - } - copy(ctx.buffer[ctx.buf_size:], data[:chk_size]) - ctx.buf_size += chk_size - length -= chk_size - data = data[chk_size:] - if ctx.buf_size == 64 { - stage2(ctx, ctx.buffer[:]) - ctx.buf_size = 0 - } - } -} - -final :: proc(ctx: ^Streebog_Context, hash: []byte) { - t: [64]byte - t[1] = byte((ctx.buf_size * 8) >> 8) & 0xff - t[0] = byte((ctx.buf_size) * 8) & 0xff - - padding(ctx) - - G(ctx.h[:], ctx.n[:], ctx.buffer[:]) - - add_mod_512(ctx.n[:], t[:], ctx.n[:]) - add_mod_512(ctx.sigma[:], ctx.buffer[:], ctx.sigma[:]) - - G(ctx.h[:], ctx.v_0[:], ctx.n[:]) - G(ctx.h[:], ctx.v_0[:], ctx.sigma[:]) - - if ctx.is256 { - copy(hash[:], ctx.h[32:]) - } else { - copy(hash[:], ctx.h[:]) - } -} - -/* - Streebog implementation -*/ - -PI := [256]byte { - 252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4, 77, - 233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205, 95, 193, - 249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1, 142, 79, - 5, 132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127, 212, 211, 31, - 235, 52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 204, - 181, 112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71, 156, 183, 93, 135, - 21, 161, 150, 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158, 178, 177, - 50, 117, 25, 61, 255, 53, 138, 126, 109, 84, 198, 128, 195, 189, 13, 87, - 223, 245, 36, 169, 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, - 224, 15, 236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 78, 51, 10, 74, - 167, 151, 96, 115, 30, 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65, - 173, 69, 70, 146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 149, 59, - 7, 88, 179, 64, 134, 172, 29, 247, 48, 55, 107, 228, 136, 217, 231, 137, - 225, 27, 131, 73, 76, 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97, - 32, 113, 103, 164, 45, 43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82, - 89, 166, 116, 210, 230, 244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182, -} - -TAU := [64]byte { - 0, 8, 16, 24, 32, 40, 48, 56, - 1, 9, 17, 25, 33, 41, 49, 57, - 2, 10, 18, 26, 34, 42, 50, 58, - 3, 11, 19, 27, 35, 43, 51, 59, - 4, 12, 20, 28, 36, 44, 52, 60, - 5, 13, 21, 29, 37, 45, 53, 61, - 6, 14, 22, 30, 38, 46, 54, 62, - 7, 15, 23, 31, 39, 47, 55, 63, -} - -STREEBOG_A := [64]u64 { - 0x8e20faa72ba0b470, 0x47107ddd9b505a38, 0xad08b0e0c3282d1c, 0xd8045870ef14980e, - 0x6c022c38f90a4c07, 0x3601161cf205268d, 0x1b8e0b0e798c13c8, 0x83478b07b2468764, - 0xa011d380818e8f40, 0x5086e740ce47c920, 0x2843fd2067adea10, 0x14aff010bdd87508, - 0x0ad97808d06cb404, 0x05e23c0468365a02, 0x8c711e02341b2d01, 0x46b60f011a83988e, - 0x90dab52a387ae76f, 0x486dd4151c3dfdb9, 0x24b86a840e90f0d2, 0x125c354207487869, - 0x092e94218d243cba, 0x8a174a9ec8121e5d, 0x4585254f64090fa0, 0xaccc9ca9328a8950, - 0x9d4df05d5f661451, 0xc0a878a0a1330aa6, 0x60543c50de970553, 0x302a1e286fc58ca7, - 0x18150f14b9ec46dd, 0x0c84890ad27623e0, 0x0642ca05693b9f70, 0x0321658cba93c138, - 0x86275df09ce8aaa8, 0x439da0784e745554, 0xafc0503c273aa42a, 0xd960281e9d1d5215, - 0xe230140fc0802984, 0x71180a8960409a42, 0xb60c05ca30204d21, 0x5b068c651810a89e, - 0x456c34887a3805b9, 0xac361a443d1c8cd2, 0x561b0d22900e4669, 0x2b838811480723ba, - 0x9bcf4486248d9f5d, 0xc3e9224312c8c1a0, 0xeffa11af0964ee50, 0xf97d86d98a327728, - 0xe4fa2054a80b329c, 0x727d102a548b194e, 0x39b008152acb8227, 0x9258048415eb419d, - 0x492c024284fbaec0, 0xaa16012142f35760, 0x550b8e9e21f7a530, 0xa48b474f9ef5dc18, - 0x70a6a56e2440598e, 0x3853dc371220a247, 0x1ca76e95091051ad, 0x0edd37c48a08a6d8, - 0x07e095624504536c, 0x8d70c431ac02a736, 0xc83862965601dd1b, 0x641c314b2b8ee083, -} - -STREEBOG_C := [12][64]byte { - { - 0x07, 0x45, 0xa6, 0xf2, 0x59, 0x65, 0x80, 0xdd, - 0x23, 0x4d, 0x74, 0xcc, 0x36, 0x74, 0x76, 0x05, - 0x15, 0xd3, 0x60, 0xa4, 0x08, 0x2a, 0x42, 0xa2, - 0x01, 0x69, 0x67, 0x92, 0x91, 0xe0, 0x7c, 0x4b, - 0xfc, 0xc4, 0x85, 0x75, 0x8d, 0xb8, 0x4e, 0x71, - 0x16, 0xd0, 0x45, 0x2e, 0x43, 0x76, 0x6a, 0x2f, - 0x1f, 0x7c, 0x65, 0xc0, 0x81, 0x2f, 0xcb, 0xeb, - 0xe9, 0xda, 0xca, 0x1e, 0xda, 0x5b, 0x08, 0xb1, - }, - { - 0xb7, 0x9b, 0xb1, 0x21, 0x70, 0x04, 0x79, 0xe6, - 0x56, 0xcd, 0xcb, 0xd7, 0x1b, 0xa2, 0xdd, 0x55, - 0xca, 0xa7, 0x0a, 0xdb, 0xc2, 0x61, 0xb5, 0x5c, - 0x58, 0x99, 0xd6, 0x12, 0x6b, 0x17, 0xb5, 0x9a, - 0x31, 0x01, 0xb5, 0x16, 0x0f, 0x5e, 0xd5, 0x61, - 0x98, 0x2b, 0x23, 0x0a, 0x72, 0xea, 0xfe, 0xf3, - 0xd7, 0xb5, 0x70, 0x0f, 0x46, 0x9d, 0xe3, 0x4f, - 0x1a, 0x2f, 0x9d, 0xa9, 0x8a, 0xb5, 0xa3, 0x6f, - }, - { - 0xb2, 0x0a, 0xba, 0x0a, 0xf5, 0x96, 0x1e, 0x99, - 0x31, 0xdb, 0x7a, 0x86, 0x43, 0xf4, 0xb6, 0xc2, - 0x09, 0xdb, 0x62, 0x60, 0x37, 0x3a, 0xc9, 0xc1, - 0xb1, 0x9e, 0x35, 0x90, 0xe4, 0x0f, 0xe2, 0xd3, - 0x7b, 0x7b, 0x29, 0xb1, 0x14, 0x75, 0xea, 0xf2, - 0x8b, 0x1f, 0x9c, 0x52, 0x5f, 0x5e, 0xf1, 0x06, - 0x35, 0x84, 0x3d, 0x6a, 0x28, 0xfc, 0x39, 0x0a, - 0xc7, 0x2f, 0xce, 0x2b, 0xac, 0xdc, 0x74, 0xf5, - }, - { - 0x2e, 0xd1, 0xe3, 0x84, 0xbc, 0xbe, 0x0c, 0x22, - 0xf1, 0x37, 0xe8, 0x93, 0xa1, 0xea, 0x53, 0x34, - 0xbe, 0x03, 0x52, 0x93, 0x33, 0x13, 0xb7, 0xd8, - 0x75, 0xd6, 0x03, 0xed, 0x82, 0x2c, 0xd7, 0xa9, - 0x3f, 0x35, 0x5e, 0x68, 0xad, 0x1c, 0x72, 0x9d, - 0x7d, 0x3c, 0x5c, 0x33, 0x7e, 0x85, 0x8e, 0x48, - 0xdd, 0xe4, 0x71, 0x5d, 0xa0, 0xe1, 0x48, 0xf9, - 0xd2, 0x66, 0x15, 0xe8, 0xb3, 0xdf, 0x1f, 0xef, - }, - { - 0x57, 0xfe, 0x6c, 0x7c, 0xfd, 0x58, 0x17, 0x60, - 0xf5, 0x63, 0xea, 0xa9, 0x7e, 0xa2, 0x56, 0x7a, - 0x16, 0x1a, 0x27, 0x23, 0xb7, 0x00, 0xff, 0xdf, - 0xa3, 0xf5, 0x3a, 0x25, 0x47, 0x17, 0xcd, 0xbf, - 0xbd, 0xff, 0x0f, 0x80, 0xd7, 0x35, 0x9e, 0x35, - 0x4a, 0x10, 0x86, 0x16, 0x1f, 0x1c, 0x15, 0x7f, - 0x63, 0x23, 0xa9, 0x6c, 0x0c, 0x41, 0x3f, 0x9a, - 0x99, 0x47, 0x47, 0xad, 0xac, 0x6b, 0xea, 0x4b, - }, - { - 0x6e, 0x7d, 0x64, 0x46, 0x7a, 0x40, 0x68, 0xfa, - 0x35, 0x4f, 0x90, 0x36, 0x72, 0xc5, 0x71, 0xbf, - 0xb6, 0xc6, 0xbe, 0xc2, 0x66, 0x1f, 0xf2, 0x0a, - 0xb4, 0xb7, 0x9a, 0x1c, 0xb7, 0xa6, 0xfa, 0xcf, - 0xc6, 0x8e, 0xf0, 0x9a, 0xb4, 0x9a, 0x7f, 0x18, - 0x6c, 0xa4, 0x42, 0x51, 0xf9, 0xc4, 0x66, 0x2d, - 0xc0, 0x39, 0x30, 0x7a, 0x3b, 0xc3, 0xa4, 0x6f, - 0xd9, 0xd3, 0x3a, 0x1d, 0xae, 0xae, 0x4f, 0xae, - }, - { - 0x93, 0xd4, 0x14, 0x3a, 0x4d, 0x56, 0x86, 0x88, - 0xf3, 0x4a, 0x3c, 0xa2, 0x4c, 0x45, 0x17, 0x35, - 0x04, 0x05, 0x4a, 0x28, 0x83, 0x69, 0x47, 0x06, - 0x37, 0x2c, 0x82, 0x2d, 0xc5, 0xab, 0x92, 0x09, - 0xc9, 0x93, 0x7a, 0x19, 0x33, 0x3e, 0x47, 0xd3, - 0xc9, 0x87, 0xbf, 0xe6, 0xc7, 0xc6, 0x9e, 0x39, - 0x54, 0x09, 0x24, 0xbf, 0xfe, 0x86, 0xac, 0x51, - 0xec, 0xc5, 0xaa, 0xee, 0x16, 0x0e, 0xc7, 0xf4, - }, - { - 0x1e, 0xe7, 0x02, 0xbf, 0xd4, 0x0d, 0x7f, 0xa4, - 0xd9, 0xa8, 0x51, 0x59, 0x35, 0xc2, 0xac, 0x36, - 0x2f, 0xc4, 0xa5, 0xd1, 0x2b, 0x8d, 0xd1, 0x69, - 0x90, 0x06, 0x9b, 0x92, 0xcb, 0x2b, 0x89, 0xf4, - 0x9a, 0xc4, 0xdb, 0x4d, 0x3b, 0x44, 0xb4, 0x89, - 0x1e, 0xde, 0x36, 0x9c, 0x71, 0xf8, 0xb7, 0x4e, - 0x41, 0x41, 0x6e, 0x0c, 0x02, 0xaa, 0xe7, 0x03, - 0xa7, 0xc9, 0x93, 0x4d, 0x42, 0x5b, 0x1f, 0x9b, - }, - { - 0xdb, 0x5a, 0x23, 0x83, 0x51, 0x44, 0x61, 0x72, - 0x60, 0x2a, 0x1f, 0xcb, 0x92, 0xdc, 0x38, 0x0e, - 0x54, 0x9c, 0x07, 0xa6, 0x9a, 0x8a, 0x2b, 0x7b, - 0xb1, 0xce, 0xb2, 0xdb, 0x0b, 0x44, 0x0a, 0x80, - 0x84, 0x09, 0x0d, 0xe0, 0xb7, 0x55, 0xd9, 0x3c, - 0x24, 0x42, 0x89, 0x25, 0x1b, 0x3a, 0x7d, 0x3a, - 0xde, 0x5f, 0x16, 0xec, 0xd8, 0x9a, 0x4c, 0x94, - 0x9b, 0x22, 0x31, 0x16, 0x54, 0x5a, 0x8f, 0x37, - }, - { - 0xed, 0x9c, 0x45, 0x98, 0xfb, 0xc7, 0xb4, 0x74, - 0xc3, 0xb6, 0x3b, 0x15, 0xd1, 0xfa, 0x98, 0x36, - 0xf4, 0x52, 0x76, 0x3b, 0x30, 0x6c, 0x1e, 0x7a, - 0x4b, 0x33, 0x69, 0xaf, 0x02, 0x67, 0xe7, 0x9f, - 0x03, 0x61, 0x33, 0x1b, 0x8a, 0xe1, 0xff, 0x1f, - 0xdb, 0x78, 0x8a, 0xff, 0x1c, 0xe7, 0x41, 0x89, - 0xf3, 0xf3, 0xe4, 0xb2, 0x48, 0xe5, 0x2a, 0x38, - 0x52, 0x6f, 0x05, 0x80, 0xa6, 0xde, 0xbe, 0xab, - }, - { - 0x1b, 0x2d, 0xf3, 0x81, 0xcd, 0xa4, 0xca, 0x6b, - 0x5d, 0xd8, 0x6f, 0xc0, 0x4a, 0x59, 0xa2, 0xde, - 0x98, 0x6e, 0x47, 0x7d, 0x1d, 0xcd, 0xba, 0xef, - 0xca, 0xb9, 0x48, 0xea, 0xef, 0x71, 0x1d, 0x8a, - 0x79, 0x66, 0x84, 0x14, 0x21, 0x80, 0x01, 0x20, - 0x61, 0x07, 0xab, 0xeb, 0xbb, 0x6b, 0xfa, 0xd8, - 0x94, 0xfe, 0x5a, 0x63, 0xcd, 0xc6, 0x02, 0x30, - 0xfb, 0x89, 0xc8, 0xef, 0xd0, 0x9e, 0xcd, 0x7b, - }, - { - 0x20, 0xd7, 0x1b, 0xf1, 0x4a, 0x92, 0xbc, 0x48, - 0x99, 0x1b, 0xb2, 0xd9, 0xd5, 0x17, 0xf4, 0xfa, - 0x52, 0x28, 0xe1, 0x88, 0xaa, 0xa4, 0x1d, 0xe7, - 0x86, 0xcc, 0x91, 0x18, 0x9d, 0xef, 0x80, 0x5d, - 0x9b, 0x9f, 0x21, 0x30, 0xd4, 0x12, 0x20, 0xf8, - 0x77, 0x1d, 0xdf, 0xbc, 0x32, 0x3c, 0xa4, 0xcd, - 0x7a, 0xb1, 0x49, 0x04, 0xb0, 0x80, 0x13, 0xd2, - 0xba, 0x31, 0x16, 0xf1, 0x67, 0xe7, 0x8e, 0x37, - }, -} - -Streebog_Context :: struct { - buffer: [64]byte, - h: [64]byte, - n: [64]byte, - sigma: [64]byte, - v_0: [64]byte, - v_512: [64]byte, - buf_size: u64, - hash_size: int, - is256: bool, -} - -add_mod_512 :: proc(first_vector, second_vector, result_vector: []byte) { - t: i32 = 0 - for i: i32 = 0; i < 64; i += 1 { - t = i32(first_vector[i]) + i32(second_vector[i]) + (t >> 8) - result_vector[i] = byte(t & 0xff) - } -} - -X :: #force_inline proc(a, k, out: []byte) { - for i := 0; i < 64; i += 1 { - out[i] = a[i] ~ k[i] - } -} - -S :: #force_inline proc(state: []byte) { - t: [64]byte - for i: i32 = 63; i >= 0; i -= 1 { - t[i] = PI[state[i]] - } - copy(state, t[:]) -} - -P :: #force_inline proc(state: []byte) { - t: [64]byte - for i: i32 = 63; i >= 0; i -= 1 { - t[i] = state[TAU[i]] - } - copy(state, t[:]) -} - -L :: #force_inline proc(state: []byte) { - ins := util.cast_slice([]u64, state) - out: [8]u64 - for i: i32 = 7; i >= 0; i -= 1 { - for j: i32 = 63; j >= 0; j -= 1 { - if (ins[i] >> u32(j)) & 1 != 0 { - out[i] ~= STREEBOG_A[63 - j] - } - } - } - copy(state, util.cast_slice([]byte, out[:])) -} - -E :: #force_inline proc(K, m, state: []byte) { - X(m, K, state) - for i: i32 = 0; i < 12; i += 1 { - S(state) - P(state) - L(state) - get_key(K, i) - X(state, K, state) - } -} - -get_key :: #force_inline proc(K: []byte, i: i32) { - X(K, STREEBOG_C[i][:], K) - S(K) - P(K) - L(K) -} - -G :: #force_inline proc(h, N, m: []byte) { - t, K: [64]byte - X(N, h, K[:]) - S(K[:]) - P(K[:]) - L(K[:]) - E(K[:], m, t[:]) - X(t[:], h, t[:]) - X(t[:], m, h) -} - -stage2 :: proc(ctx: ^Streebog_Context, m: []byte) { - G(ctx.h[:], ctx.n[:], m) - add_mod_512(ctx.n[:], ctx.v_512[:], ctx.n[:]) - add_mod_512(ctx.sigma[:], m, ctx.sigma[:]) -} - -padding :: proc(ctx: ^Streebog_Context) { - if ctx.buf_size < 64 { - t: [64]byte - copy(t[:], ctx.buffer[:int(ctx.buf_size)]) - t[ctx.buf_size] = 0x01 - copy(ctx.buffer[:], t[:]) - } -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 74ac7401e..f26672514 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -35,7 +35,6 @@ import sha2 "core:crypto/sha2" import sha3 "core:crypto/sha3" import shake "core:crypto/shake" import sm3 "core:crypto/sm3" -import streebog "core:crypto/streebog" import tiger "core:crypto/tiger" import tiger2 "core:crypto/tiger2" import crypto_util "core:crypto/util" @@ -154,7 +153,6 @@ _ :: sha2 _ :: sha3 _ :: shake _ :: sm3 -_ :: streebog _ :: tiger _ :: tiger2 _ :: crypto_util diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 432059f6a..bcfd15609 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -10,7 +10,6 @@ import sha3 "vendor:botan/sha3" import shake "vendor:botan/shake" import siphash "vendor:botan/siphash" import sm3 "vendor:botan/sm3" -import streebog "vendor:botan/streebog" import tiger "vendor:botan/tiger" import whirlpool "vendor:botan/whirlpool" @@ -52,7 +51,6 @@ _ :: sha3 _ :: shake _ :: siphash _ :: sm3 -_ :: streebog _ :: tiger _ :: whirlpool diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 362d79d2b..adb2bf0d9 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -27,7 +27,6 @@ import "core:crypto/blake2b" import "core:crypto/blake2s" import "core:crypto/tiger" import "core:crypto/tiger2" -import "core:crypto/streebog" import "core:crypto/sm3" import "core:crypto/siphash" import "core:os" @@ -73,8 +72,6 @@ main :: proc() { test_keccak_384(&t) test_keccak_512(&t) test_whirlpool(&t) - test_streebog_256(&t) - test_streebog_512(&t) test_blake2b(&t) test_blake2s(&t) test_tiger_128(&t) @@ -453,34 +450,6 @@ test_whirlpool :: proc(t: ^testing.T) { } } -@(test) -test_streebog_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, - TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, - TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_streebog_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, - TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, - TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_blake2b :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 99d4e5c3f..9350486a9 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -26,7 +26,6 @@ import "vendor:botan/shake" import "vendor:botan/whirlpool" import "vendor:botan/blake2b" import "vendor:botan/tiger" -import "vendor:botan/streebog" import "vendor:botan/sm3" import "vendor:botan/siphash" @@ -69,8 +68,6 @@ main :: proc() { // test_shake_256(&t) test_keccak_512(&t) test_whirlpool(&t) - test_streebog_256(&t) - test_streebog_512(&t) test_blake2b(&t) // test_tiger_128(&t) // test_tiger_160(&t) @@ -373,34 +370,6 @@ test_whirlpool :: proc(t: ^testing.T) { } } -@(test) -test_streebog_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, - TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, - TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_streebog_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, - TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, - TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_blake2b :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/vendor/botan/README.md b/vendor/botan/README.md index 6d1087cbf..ec733d47a 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -16,7 +16,6 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | -| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ | | [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | | [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 7f3dc99b9..a006977c2 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -80,8 +80,6 @@ HASH_MD5 :: "MD5" HASH_TIGER_128 :: "Tiger(16,3)" HASH_TIGER_160 :: "Tiger(20,3)" HASH_TIGER_192 :: "Tiger(24,3)" -HASH_STREEBOG_256 :: "Streebog-256" -HASH_STREEBOG_512 :: "Streebog-512" HASH_SM3 :: "SM3" MAC_HMAC_SHA1 :: "HMAC(SHA1)" diff --git a/vendor/botan/streebog/streebog.odin b/vendor/botan/streebog/streebog.odin deleted file mode 100644 index 07c39684a..000000000 --- a/vendor/botan/streebog/streebog.odin +++ /dev/null @@ -1,204 +0,0 @@ -package vendor_streebog - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial implementation. - - Interface for the Streebog hashing algorithm. - The hash will be computed via bindings to the Botan crypto library -*/ - -import "core:os" -import "core:io" - -import botan "../bindings" - -/* - High level API -*/ - -DIGEST_SIZE_256 :: 32 -DIGEST_SIZE_512 :: 64 - -// hash_string_256 will hash the given input and return the -// computed hash -hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { - return hash_bytes_256(transmute([]byte)(data)) -} - -// hash_bytes_256 will hash the given input and return the -// computed hash -hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { - hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_STREEBOG_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_256 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_256(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_256 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_STREEBOG_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_256 will read the stream in chunks and compute a -// hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { - hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_STREEBOG_256, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_256 will read the file provided by the given handle -// and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { - if !load_at_once { - return hash_stream_256(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_256(buf[:]), ok - } - } - return [DIGEST_SIZE_256]byte{}, false -} - -hash_256 :: proc { - hash_stream_256, - hash_file_256, - hash_bytes_256, - hash_string_256, - hash_bytes_to_buffer_256, - hash_string_to_buffer_256, -} - -// hash_string_512 will hash the given input and return the -// computed hash -hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { - return hash_bytes_512(transmute([]byte)(data)) -} - -// hash_bytes_512 will hash the given input and return the -// computed hash -hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { - hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_STREEBOG_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_512 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_512(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_512 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_STREEBOG_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_512 will read the stream in chunks and compute a -// hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { - hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_STREEBOG_512, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_512 will read the file provided by the given handle -// and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { - if !load_at_once { - return hash_stream_512(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_512(buf[:]), ok - } - } - return [DIGEST_SIZE_512]byte{}, false -} - -hash_512 :: proc { - hash_stream_512, - hash_file_512, - hash_bytes_512, - hash_string_512, - hash_bytes_to_buffer_512, - hash_string_to_buffer_512, -} - -/* - Low level API -*/ - -Streebog_Context :: botan.hash_t - -init :: proc "contextless" (ctx: ^botan.hash_t, hash_size := 512) { - switch hash_size { - case 256: botan.hash_init(ctx, botan.HASH_STREEBOG_256, 0) - case 512: botan.hash_init(ctx, botan.HASH_STREEBOG_512, 0) - } -} - -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { - botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) -} - -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { - botan.hash_final(ctx^, &hash[0]) - botan.hash_destroy(ctx^) -} \ No newline at end of file From 0b8603848250e3f321690cb27e8daa9080701890 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 21:59:15 +0900 Subject: [PATCH 099/160] core/crypto/tiger: Remove, historical/exotic --- core/crypto/README.md | 2 - core/crypto/_tiger/tiger.odin | 410 ---------------------- core/crypto/tiger/tiger.odin | 280 --------------- core/crypto/tiger2/tiger2.odin | 280 --------------- examples/all/all_main.odin | 4 - examples/all/all_vendor.odin | 2 - tests/core/crypto/test_core_crypto.odin | 110 ------ tests/vendor/botan/test_vendor_botan.odin | 64 ---- vendor/botan/README.md | 1 - vendor/botan/bindings/botan.odin | 3 - vendor/botan/tiger/tiger.odin | 285 --------------- 11 files changed, 1441 deletions(-) delete mode 100644 core/crypto/_tiger/tiger.odin delete mode 100644 core/crypto/tiger/tiger.odin delete mode 100644 core/crypto/tiger2/tiger2.odin delete mode 100644 vendor/botan/tiger/tiger.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index eaf8c13e2..402d5605f 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -17,8 +17,6 @@ Please see the chart below for the options. | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | -| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | -| [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | | [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | #### High level API diff --git a/core/crypto/_tiger/tiger.odin b/core/crypto/_tiger/tiger.odin deleted file mode 100644 index e1629c4ca..000000000 --- a/core/crypto/_tiger/tiger.odin +++ /dev/null @@ -1,410 +0,0 @@ -package _tiger - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the Tiger hashing algorithm, as defined in -*/ - -import "../util" - -T1 := [?]u64 { - 0x02aab17cf7e90c5e, 0xac424b03e243a8ec, 0x72cd5be30dd5fcd3, 0x6d019b93f6f97f3a, - 0xcd9978ffd21f9193, 0x7573a1c9708029e2, 0xb164326b922a83c3, 0x46883eee04915870, - 0xeaace3057103ece6, 0xc54169b808a3535c, 0x4ce754918ddec47c, 0x0aa2f4dfdc0df40c, - 0x10b76f18a74dbefa, 0xc6ccb6235ad1ab6a, 0x13726121572fe2ff, 0x1a488c6f199d921e, - 0x4bc9f9f4da0007ca, 0x26f5e6f6e85241c7, 0x859079dbea5947b6, 0x4f1885c5c99e8c92, - 0xd78e761ea96f864b, 0x8e36428c52b5c17d, 0x69cf6827373063c1, 0xb607c93d9bb4c56e, - 0x7d820e760e76b5ea, 0x645c9cc6f07fdc42, 0xbf38a078243342e0, 0x5f6b343c9d2e7d04, - 0xf2c28aeb600b0ec6, 0x6c0ed85f7254bcac, 0x71592281a4db4fe5, 0x1967fa69ce0fed9f, - 0xfd5293f8b96545db, 0xc879e9d7f2a7600b, 0x860248920193194e, 0xa4f9533b2d9cc0b3, - 0x9053836c15957613, 0xdb6dcf8afc357bf1, 0x18beea7a7a370f57, 0x037117ca50b99066, - 0x6ab30a9774424a35, 0xf4e92f02e325249b, 0x7739db07061ccae1, 0xd8f3b49ceca42a05, - 0xbd56be3f51382f73, 0x45faed5843b0bb28, 0x1c813d5c11bf1f83, 0x8af0e4b6d75fa169, - 0x33ee18a487ad9999, 0x3c26e8eab1c94410, 0xb510102bc0a822f9, 0x141eef310ce6123b, - 0xfc65b90059ddb154, 0xe0158640c5e0e607, 0x884e079826c3a3cf, 0x930d0d9523c535fd, - 0x35638d754e9a2b00, 0x4085fccf40469dd5, 0xc4b17ad28be23a4c, 0xcab2f0fc6a3e6a2e, - 0x2860971a6b943fcd, 0x3dde6ee212e30446, 0x6222f32ae01765ae, 0x5d550bb5478308fe, - 0xa9efa98da0eda22a, 0xc351a71686c40da7, 0x1105586d9c867c84, 0xdcffee85fda22853, - 0xccfbd0262c5eef76, 0xbaf294cb8990d201, 0xe69464f52afad975, 0x94b013afdf133e14, - 0x06a7d1a32823c958, 0x6f95fe5130f61119, 0xd92ab34e462c06c0, 0xed7bde33887c71d2, - 0x79746d6e6518393e, 0x5ba419385d713329, 0x7c1ba6b948a97564, 0x31987c197bfdac67, - 0xde6c23c44b053d02, 0x581c49fed002d64d, 0xdd474d6338261571, 0xaa4546c3e473d062, - 0x928fce349455f860, 0x48161bbacaab94d9, 0x63912430770e6f68, 0x6ec8a5e602c6641c, - 0x87282515337ddd2b, 0x2cda6b42034b701b, 0xb03d37c181cb096d, 0xe108438266c71c6f, - 0x2b3180c7eb51b255, 0xdf92b82f96c08bbc, 0x5c68c8c0a632f3ba, 0x5504cc861c3d0556, - 0xabbfa4e55fb26b8f, 0x41848b0ab3baceb4, 0xb334a273aa445d32, 0xbca696f0a85ad881, - 0x24f6ec65b528d56c, 0x0ce1512e90f4524a, 0x4e9dd79d5506d35a, 0x258905fac6ce9779, - 0x2019295b3e109b33, 0xf8a9478b73a054cc, 0x2924f2f934417eb0, 0x3993357d536d1bc4, - 0x38a81ac21db6ff8b, 0x47c4fbf17d6016bf, 0x1e0faadd7667e3f5, 0x7abcff62938beb96, - 0xa78dad948fc179c9, 0x8f1f98b72911e50d, 0x61e48eae27121a91, 0x4d62f7ad31859808, - 0xeceba345ef5ceaeb, 0xf5ceb25ebc9684ce, 0xf633e20cb7f76221, 0xa32cdf06ab8293e4, - 0x985a202ca5ee2ca4, 0xcf0b8447cc8a8fb1, 0x9f765244979859a3, 0xa8d516b1a1240017, - 0x0bd7ba3ebb5dc726, 0xe54bca55b86adb39, 0x1d7a3afd6c478063, 0x519ec608e7669edd, - 0x0e5715a2d149aa23, 0x177d4571848ff194, 0xeeb55f3241014c22, 0x0f5e5ca13a6e2ec2, - 0x8029927b75f5c361, 0xad139fabc3d6e436, 0x0d5df1a94ccf402f, 0x3e8bd948bea5dfc8, - 0xa5a0d357bd3ff77e, 0xa2d12e251f74f645, 0x66fd9e525e81a082, 0x2e0c90ce7f687a49, - 0xc2e8bcbeba973bc5, 0x000001bce509745f, 0x423777bbe6dab3d6, 0xd1661c7eaef06eb5, - 0xa1781f354daacfd8, 0x2d11284a2b16affc, 0xf1fc4f67fa891d1f, 0x73ecc25dcb920ada, - 0xae610c22c2a12651, 0x96e0a810d356b78a, 0x5a9a381f2fe7870f, 0xd5ad62ede94e5530, - 0xd225e5e8368d1427, 0x65977b70c7af4631, 0x99f889b2de39d74f, 0x233f30bf54e1d143, - 0x9a9675d3d9a63c97, 0x5470554ff334f9a8, 0x166acb744a4f5688, 0x70c74caab2e4aead, - 0xf0d091646f294d12, 0x57b82a89684031d1, 0xefd95a5a61be0b6b, 0x2fbd12e969f2f29a, - 0x9bd37013feff9fe8, 0x3f9b0404d6085a06, 0x4940c1f3166cfe15, 0x09542c4dcdf3defb, - 0xb4c5218385cd5ce3, 0xc935b7dc4462a641, 0x3417f8a68ed3b63f, 0xb80959295b215b40, - 0xf99cdaef3b8c8572, 0x018c0614f8fcb95d, 0x1b14accd1a3acdf3, 0x84d471f200bb732d, - 0xc1a3110e95e8da16, 0x430a7220bf1a82b8, 0xb77e090d39df210e, 0x5ef4bd9f3cd05e9d, - 0x9d4ff6da7e57a444, 0xda1d60e183d4a5f8, 0xb287c38417998e47, 0xfe3edc121bb31886, - 0xc7fe3ccc980ccbef, 0xe46fb590189bfd03, 0x3732fd469a4c57dc, 0x7ef700a07cf1ad65, - 0x59c64468a31d8859, 0x762fb0b4d45b61f6, 0x155baed099047718, 0x68755e4c3d50baa6, - 0xe9214e7f22d8b4df, 0x2addbf532eac95f4, 0x32ae3909b4bd0109, 0x834df537b08e3450, - 0xfa209da84220728d, 0x9e691d9b9efe23f7, 0x0446d288c4ae8d7f, 0x7b4cc524e169785b, - 0x21d87f0135ca1385, 0xcebb400f137b8aa5, 0x272e2b66580796be, 0x3612264125c2b0de, - 0x057702bdad1efbb2, 0xd4babb8eacf84be9, 0x91583139641bc67b, 0x8bdc2de08036e024, - 0x603c8156f49f68ed, 0xf7d236f7dbef5111, 0x9727c4598ad21e80, 0xa08a0896670a5fd7, - 0xcb4a8f4309eba9cb, 0x81af564b0f7036a1, 0xc0b99aa778199abd, 0x959f1ec83fc8e952, - 0x8c505077794a81b9, 0x3acaaf8f056338f0, 0x07b43f50627a6778, 0x4a44ab49f5eccc77, - 0x3bc3d6e4b679ee98, 0x9cc0d4d1cf14108c, 0x4406c00b206bc8a0, 0x82a18854c8d72d89, - 0x67e366b35c3c432c, 0xb923dd61102b37f2, 0x56ab2779d884271d, 0xbe83e1b0ff1525af, - 0xfb7c65d4217e49a9, 0x6bdbe0e76d48e7d4, 0x08df828745d9179e, 0x22ea6a9add53bd34, - 0xe36e141c5622200a, 0x7f805d1b8cb750ee, 0xafe5c7a59f58e837, 0xe27f996a4fb1c23c, - 0xd3867dfb0775f0d0, 0xd0e673de6e88891a, 0x123aeb9eafb86c25, 0x30f1d5d5c145b895, - 0xbb434a2dee7269e7, 0x78cb67ecf931fa38, 0xf33b0372323bbf9c, 0x52d66336fb279c74, - 0x505f33ac0afb4eaa, 0xe8a5cd99a2cce187, 0x534974801e2d30bb, 0x8d2d5711d5876d90, - 0x1f1a412891bc038e, 0xd6e2e71d82e56648, 0x74036c3a497732b7, 0x89b67ed96361f5ab, - 0xffed95d8f1ea02a2, 0xe72b3bd61464d43d, 0xa6300f170bdc4820, 0xebc18760ed78a77a, -} - -T2 := [?]u64 { - 0xe6a6be5a05a12138, 0xb5a122a5b4f87c98, 0x563c6089140b6990, 0x4c46cb2e391f5dd5, - 0xd932addbc9b79434, 0x08ea70e42015aff5, 0xd765a6673e478cf1, 0xc4fb757eab278d99, - 0xdf11c6862d6e0692, 0xddeb84f10d7f3b16, 0x6f2ef604a665ea04, 0x4a8e0f0ff0e0dfb3, - 0xa5edeef83dbcba51, 0xfc4f0a2a0ea4371e, 0xe83e1da85cb38429, 0xdc8ff882ba1b1ce2, - 0xcd45505e8353e80d, 0x18d19a00d4db0717, 0x34a0cfeda5f38101, 0x0be77e518887caf2, - 0x1e341438b3c45136, 0xe05797f49089ccf9, 0xffd23f9df2591d14, 0x543dda228595c5cd, - 0x661f81fd99052a33, 0x8736e641db0f7b76, 0x15227725418e5307, 0xe25f7f46162eb2fa, - 0x48a8b2126c13d9fe, 0xafdc541792e76eea, 0x03d912bfc6d1898f, 0x31b1aafa1b83f51b, - 0xf1ac2796e42ab7d9, 0x40a3a7d7fcd2ebac, 0x1056136d0afbbcc5, 0x7889e1dd9a6d0c85, - 0xd33525782a7974aa, 0xa7e25d09078ac09b, 0xbd4138b3eac6edd0, 0x920abfbe71eb9e70, - 0xa2a5d0f54fc2625c, 0xc054e36b0b1290a3, 0xf6dd59ff62fe932b, 0x3537354511a8ac7d, - 0xca845e9172fadcd4, 0x84f82b60329d20dc, 0x79c62ce1cd672f18, 0x8b09a2add124642c, - 0xd0c1e96a19d9e726, 0x5a786a9b4ba9500c, 0x0e020336634c43f3, 0xc17b474aeb66d822, - 0x6a731ae3ec9baac2, 0x8226667ae0840258, 0x67d4567691caeca5, 0x1d94155c4875adb5, - 0x6d00fd985b813fdf, 0x51286efcb774cd06, 0x5e8834471fa744af, 0xf72ca0aee761ae2e, - 0xbe40e4cdaee8e09a, 0xe9970bbb5118f665, 0x726e4beb33df1964, 0x703b000729199762, - 0x4631d816f5ef30a7, 0xb880b5b51504a6be, 0x641793c37ed84b6c, 0x7b21ed77f6e97d96, - 0x776306312ef96b73, 0xae528948e86ff3f4, 0x53dbd7f286a3f8f8, 0x16cadce74cfc1063, - 0x005c19bdfa52c6dd, 0x68868f5d64d46ad3, 0x3a9d512ccf1e186a, 0x367e62c2385660ae, - 0xe359e7ea77dcb1d7, 0x526c0773749abe6e, 0x735ae5f9d09f734b, 0x493fc7cc8a558ba8, - 0xb0b9c1533041ab45, 0x321958ba470a59bd, 0x852db00b5f46c393, 0x91209b2bd336b0e5, - 0x6e604f7d659ef19f, 0xb99a8ae2782ccb24, 0xccf52ab6c814c4c7, 0x4727d9afbe11727b, - 0x7e950d0c0121b34d, 0x756f435670ad471f, 0xf5add442615a6849, 0x4e87e09980b9957a, - 0x2acfa1df50aee355, 0xd898263afd2fd556, 0xc8f4924dd80c8fd6, 0xcf99ca3d754a173a, - 0xfe477bacaf91bf3c, 0xed5371f6d690c12d, 0x831a5c285e687094, 0xc5d3c90a3708a0a4, - 0x0f7f903717d06580, 0x19f9bb13b8fdf27f, 0xb1bd6f1b4d502843, 0x1c761ba38fff4012, - 0x0d1530c4e2e21f3b, 0x8943ce69a7372c8a, 0xe5184e11feb5ce66, 0x618bdb80bd736621, - 0x7d29bad68b574d0b, 0x81bb613e25e6fe5b, 0x071c9c10bc07913f, 0xc7beeb7909ac2d97, - 0xc3e58d353bc5d757, 0xeb017892f38f61e8, 0xd4effb9c9b1cc21a, 0x99727d26f494f7ab, - 0xa3e063a2956b3e03, 0x9d4a8b9a4aa09c30, 0x3f6ab7d500090fb4, 0x9cc0f2a057268ac0, - 0x3dee9d2dedbf42d1, 0x330f49c87960a972, 0xc6b2720287421b41, 0x0ac59ec07c00369c, - 0xef4eac49cb353425, 0xf450244eef0129d8, 0x8acc46e5caf4deb6, 0x2ffeab63989263f7, - 0x8f7cb9fe5d7a4578, 0x5bd8f7644e634635, 0x427a7315bf2dc900, 0x17d0c4aa2125261c, - 0x3992486c93518e50, 0xb4cbfee0a2d7d4c3, 0x7c75d6202c5ddd8d, 0xdbc295d8e35b6c61, - 0x60b369d302032b19, 0xce42685fdce44132, 0x06f3ddb9ddf65610, 0x8ea4d21db5e148f0, - 0x20b0fce62fcd496f, 0x2c1b912358b0ee31, 0xb28317b818f5a308, 0xa89c1e189ca6d2cf, - 0x0c6b18576aaadbc8, 0xb65deaa91299fae3, 0xfb2b794b7f1027e7, 0x04e4317f443b5beb, - 0x4b852d325939d0a6, 0xd5ae6beefb207ffc, 0x309682b281c7d374, 0xbae309a194c3b475, - 0x8cc3f97b13b49f05, 0x98a9422ff8293967, 0x244b16b01076ff7c, 0xf8bf571c663d67ee, - 0x1f0d6758eee30da1, 0xc9b611d97adeb9b7, 0xb7afd5887b6c57a2, 0x6290ae846b984fe1, - 0x94df4cdeacc1a5fd, 0x058a5bd1c5483aff, 0x63166cc142ba3c37, 0x8db8526eb2f76f40, - 0xe10880036f0d6d4e, 0x9e0523c9971d311d, 0x45ec2824cc7cd691, 0x575b8359e62382c9, - 0xfa9e400dc4889995, 0xd1823ecb45721568, 0xdafd983b8206082f, 0xaa7d29082386a8cb, - 0x269fcd4403b87588, 0x1b91f5f728bdd1e0, 0xe4669f39040201f6, 0x7a1d7c218cf04ade, - 0x65623c29d79ce5ce, 0x2368449096c00bb1, 0xab9bf1879da503ba, 0xbc23ecb1a458058e, - 0x9a58df01bb401ecc, 0xa070e868a85f143d, 0x4ff188307df2239e, 0x14d565b41a641183, - 0xee13337452701602, 0x950e3dcf3f285e09, 0x59930254b9c80953, 0x3bf299408930da6d, - 0xa955943f53691387, 0xa15edecaa9cb8784, 0x29142127352be9a0, 0x76f0371fff4e7afb, - 0x0239f450274f2228, 0xbb073af01d5e868b, 0xbfc80571c10e96c1, 0xd267088568222e23, - 0x9671a3d48e80b5b0, 0x55b5d38ae193bb81, 0x693ae2d0a18b04b8, 0x5c48b4ecadd5335f, - 0xfd743b194916a1ca, 0x2577018134be98c4, 0xe77987e83c54a4ad, 0x28e11014da33e1b9, - 0x270cc59e226aa213, 0x71495f756d1a5f60, 0x9be853fb60afef77, 0xadc786a7f7443dbf, - 0x0904456173b29a82, 0x58bc7a66c232bd5e, 0xf306558c673ac8b2, 0x41f639c6b6c9772a, - 0x216defe99fda35da, 0x11640cc71c7be615, 0x93c43694565c5527, 0xea038e6246777839, - 0xf9abf3ce5a3e2469, 0x741e768d0fd312d2, 0x0144b883ced652c6, 0xc20b5a5ba33f8552, - 0x1ae69633c3435a9d, 0x97a28ca4088cfdec, 0x8824a43c1e96f420, 0x37612fa66eeea746, - 0x6b4cb165f9cf0e5a, 0x43aa1c06a0abfb4a, 0x7f4dc26ff162796b, 0x6cbacc8e54ed9b0f, - 0xa6b7ffefd2bb253e, 0x2e25bc95b0a29d4f, 0x86d6a58bdef1388c, 0xded74ac576b6f054, - 0x8030bdbc2b45805d, 0x3c81af70e94d9289, 0x3eff6dda9e3100db, 0xb38dc39fdfcc8847, - 0x123885528d17b87e, 0xf2da0ed240b1b642, 0x44cefadcd54bf9a9, 0x1312200e433c7ee6, - 0x9ffcc84f3a78c748, 0xf0cd1f72248576bb, 0xec6974053638cfe4, 0x2ba7b67c0cec4e4c, - 0xac2f4df3e5ce32ed, 0xcb33d14326ea4c11, 0xa4e9044cc77e58bc, 0x5f513293d934fcef, - 0x5dc9645506e55444, 0x50de418f317de40a, 0x388cb31a69dde259, 0x2db4a83455820a86, - 0x9010a91e84711ae9, 0x4df7f0b7b1498371, 0xd62a2eabc0977179, 0x22fac097aa8d5c0e, -} - -T3 := [?]u64 { - 0xf49fcc2ff1daf39b, 0x487fd5c66ff29281, 0xe8a30667fcdca83f, 0x2c9b4be3d2fcce63, - 0xda3ff74b93fbbbc2, 0x2fa165d2fe70ba66, 0xa103e279970e93d4, 0xbecdec77b0e45e71, - 0xcfb41e723985e497, 0xb70aaa025ef75017, 0xd42309f03840b8e0, 0x8efc1ad035898579, - 0x96c6920be2b2abc5, 0x66af4163375a9172, 0x2174abdcca7127fb, 0xb33ccea64a72ff41, - 0xf04a4933083066a5, 0x8d970acdd7289af5, 0x8f96e8e031c8c25e, 0xf3fec02276875d47, - 0xec7bf310056190dd, 0xf5adb0aebb0f1491, 0x9b50f8850fd58892, 0x4975488358b74de8, - 0xa3354ff691531c61, 0x0702bbe481d2c6ee, 0x89fb24057deded98, 0xac3075138596e902, - 0x1d2d3580172772ed, 0xeb738fc28e6bc30d, 0x5854ef8f63044326, 0x9e5c52325add3bbe, - 0x90aa53cf325c4623, 0xc1d24d51349dd067, 0x2051cfeea69ea624, 0x13220f0a862e7e4f, - 0xce39399404e04864, 0xd9c42ca47086fcb7, 0x685ad2238a03e7cc, 0x066484b2ab2ff1db, - 0xfe9d5d70efbf79ec, 0x5b13b9dd9c481854, 0x15f0d475ed1509ad, 0x0bebcd060ec79851, - 0xd58c6791183ab7f8, 0xd1187c5052f3eee4, 0xc95d1192e54e82ff, 0x86eea14cb9ac6ca2, - 0x3485beb153677d5d, 0xdd191d781f8c492a, 0xf60866baa784ebf9, 0x518f643ba2d08c74, - 0x8852e956e1087c22, 0xa768cb8dc410ae8d, 0x38047726bfec8e1a, 0xa67738b4cd3b45aa, - 0xad16691cec0dde19, 0xc6d4319380462e07, 0xc5a5876d0ba61938, 0x16b9fa1fa58fd840, - 0x188ab1173ca74f18, 0xabda2f98c99c021f, 0x3e0580ab134ae816, 0x5f3b05b773645abb, - 0x2501a2be5575f2f6, 0x1b2f74004e7e8ba9, 0x1cd7580371e8d953, 0x7f6ed89562764e30, - 0xb15926ff596f003d, 0x9f65293da8c5d6b9, 0x6ecef04dd690f84c, 0x4782275fff33af88, - 0xe41433083f820801, 0xfd0dfe409a1af9b5, 0x4325a3342cdb396b, 0x8ae77e62b301b252, - 0xc36f9e9f6655615a, 0x85455a2d92d32c09, 0xf2c7dea949477485, 0x63cfb4c133a39eba, - 0x83b040cc6ebc5462, 0x3b9454c8fdb326b0, 0x56f56a9e87ffd78c, 0x2dc2940d99f42bc6, - 0x98f7df096b096e2d, 0x19a6e01e3ad852bf, 0x42a99ccbdbd4b40b, 0xa59998af45e9c559, - 0x366295e807d93186, 0x6b48181bfaa1f773, 0x1fec57e2157a0a1d, 0x4667446af6201ad5, - 0xe615ebcacfb0f075, 0xb8f31f4f68290778, 0x22713ed6ce22d11e, 0x3057c1a72ec3c93b, - 0xcb46acc37c3f1f2f, 0xdbb893fd02aaf50e, 0x331fd92e600b9fcf, 0xa498f96148ea3ad6, - 0xa8d8426e8b6a83ea, 0xa089b274b7735cdc, 0x87f6b3731e524a11, 0x118808e5cbc96749, - 0x9906e4c7b19bd394, 0xafed7f7e9b24a20c, 0x6509eadeeb3644a7, 0x6c1ef1d3e8ef0ede, - 0xb9c97d43e9798fb4, 0xa2f2d784740c28a3, 0x7b8496476197566f, 0x7a5be3e6b65f069d, - 0xf96330ed78be6f10, 0xeee60de77a076a15, 0x2b4bee4aa08b9bd0, 0x6a56a63ec7b8894e, - 0x02121359ba34fef4, 0x4cbf99f8283703fc, 0x398071350caf30c8, 0xd0a77a89f017687a, - 0xf1c1a9eb9e423569, 0x8c7976282dee8199, 0x5d1737a5dd1f7abd, 0x4f53433c09a9fa80, - 0xfa8b0c53df7ca1d9, 0x3fd9dcbc886ccb77, 0xc040917ca91b4720, 0x7dd00142f9d1dcdf, - 0x8476fc1d4f387b58, 0x23f8e7c5f3316503, 0x032a2244e7e37339, 0x5c87a5d750f5a74b, - 0x082b4cc43698992e, 0xdf917becb858f63c, 0x3270b8fc5bf86dda, 0x10ae72bb29b5dd76, - 0x576ac94e7700362b, 0x1ad112dac61efb8f, 0x691bc30ec5faa427, 0xff246311cc327143, - 0x3142368e30e53206, 0x71380e31e02ca396, 0x958d5c960aad76f1, 0xf8d6f430c16da536, - 0xc8ffd13f1be7e1d2, 0x7578ae66004ddbe1, 0x05833f01067be646, 0xbb34b5ad3bfe586d, - 0x095f34c9a12b97f0, 0x247ab64525d60ca8, 0xdcdbc6f3017477d1, 0x4a2e14d4decad24d, - 0xbdb5e6d9be0a1eeb, 0x2a7e70f7794301ab, 0xdef42d8a270540fd, 0x01078ec0a34c22c1, - 0xe5de511af4c16387, 0x7ebb3a52bd9a330a, 0x77697857aa7d6435, 0x004e831603ae4c32, - 0xe7a21020ad78e312, 0x9d41a70c6ab420f2, 0x28e06c18ea1141e6, 0xd2b28cbd984f6b28, - 0x26b75f6c446e9d83, 0xba47568c4d418d7f, 0xd80badbfe6183d8e, 0x0e206d7f5f166044, - 0xe258a43911cbca3e, 0x723a1746b21dc0bc, 0xc7caa854f5d7cdd3, 0x7cac32883d261d9c, - 0x7690c26423ba942c, 0x17e55524478042b8, 0xe0be477656a2389f, 0x4d289b5e67ab2da0, - 0x44862b9c8fbbfd31, 0xb47cc8049d141365, 0x822c1b362b91c793, 0x4eb14655fb13dfd8, - 0x1ecbba0714e2a97b, 0x6143459d5cde5f14, 0x53a8fbf1d5f0ac89, 0x97ea04d81c5e5b00, - 0x622181a8d4fdb3f3, 0xe9bcd341572a1208, 0x1411258643cce58a, 0x9144c5fea4c6e0a4, - 0x0d33d06565cf620f, 0x54a48d489f219ca1, 0xc43e5eac6d63c821, 0xa9728b3a72770daf, - 0xd7934e7b20df87ef, 0xe35503b61a3e86e5, 0xcae321fbc819d504, 0x129a50b3ac60bfa6, - 0xcd5e68ea7e9fb6c3, 0xb01c90199483b1c7, 0x3de93cd5c295376c, 0xaed52edf2ab9ad13, - 0x2e60f512c0a07884, 0xbc3d86a3e36210c9, 0x35269d9b163951ce, 0x0c7d6e2ad0cdb5fa, - 0x59e86297d87f5733, 0x298ef221898db0e7, 0x55000029d1a5aa7e, 0x8bc08ae1b5061b45, - 0xc2c31c2b6c92703a, 0x94cc596baf25ef42, 0x0a1d73db22540456, 0x04b6a0f9d9c4179a, - 0xeffdafa2ae3d3c60, 0xf7c8075bb49496c4, 0x9cc5c7141d1cd4e3, 0x78bd1638218e5534, - 0xb2f11568f850246a, 0xedfabcfa9502bc29, 0x796ce5f2da23051b, 0xaae128b0dc93537c, - 0x3a493da0ee4b29ae, 0xb5df6b2c416895d7, 0xfcabbd25122d7f37, 0x70810b58105dc4b1, - 0xe10fdd37f7882a90, 0x524dcab5518a3f5c, 0x3c9e85878451255b, 0x4029828119bd34e2, - 0x74a05b6f5d3ceccb, 0xb610021542e13eca, 0x0ff979d12f59e2ac, 0x6037da27e4f9cc50, - 0x5e92975a0df1847d, 0xd66de190d3e623fe, 0x5032d6b87b568048, 0x9a36b7ce8235216e, - 0x80272a7a24f64b4a, 0x93efed8b8c6916f7, 0x37ddbff44cce1555, 0x4b95db5d4b99bd25, - 0x92d3fda169812fc0, 0xfb1a4a9a90660bb6, 0x730c196946a4b9b2, 0x81e289aa7f49da68, - 0x64669a0f83b1a05f, 0x27b3ff7d9644f48b, 0xcc6b615c8db675b3, 0x674f20b9bcebbe95, - 0x6f31238275655982, 0x5ae488713e45cf05, 0xbf619f9954c21157, 0xeabac46040a8eae9, - 0x454c6fe9f2c0c1cd, 0x419cf6496412691c, 0xd3dc3bef265b0f70, 0x6d0e60f5c3578a9e, -} - -T4 := [?]u64 { - 0x5b0e608526323c55, 0x1a46c1a9fa1b59f5, 0xa9e245a17c4c8ffa, 0x65ca5159db2955d7, - 0x05db0a76ce35afc2, 0x81eac77ea9113d45, 0x528ef88ab6ac0a0d, 0xa09ea253597be3ff, - 0x430ddfb3ac48cd56, 0xc4b3a67af45ce46f, 0x4ececfd8fbe2d05e, 0x3ef56f10b39935f0, - 0x0b22d6829cd619c6, 0x17fd460a74df2069, 0x6cf8cc8e8510ed40, 0xd6c824bf3a6ecaa7, - 0x61243d581a817049, 0x048bacb6bbc163a2, 0xd9a38ac27d44cc32, 0x7fddff5baaf410ab, - 0xad6d495aa804824b, 0xe1a6a74f2d8c9f94, 0xd4f7851235dee8e3, 0xfd4b7f886540d893, - 0x247c20042aa4bfda, 0x096ea1c517d1327c, 0xd56966b4361a6685, 0x277da5c31221057d, - 0x94d59893a43acff7, 0x64f0c51ccdc02281, 0x3d33bcc4ff6189db, 0xe005cb184ce66af1, - 0xff5ccd1d1db99bea, 0xb0b854a7fe42980f, 0x7bd46a6a718d4b9f, 0xd10fa8cc22a5fd8c, - 0xd31484952be4bd31, 0xc7fa975fcb243847, 0x4886ed1e5846c407, 0x28cddb791eb70b04, - 0xc2b00be2f573417f, 0x5c9590452180f877, 0x7a6bddfff370eb00, 0xce509e38d6d9d6a4, - 0xebeb0f00647fa702, 0x1dcc06cf76606f06, 0xe4d9f28ba286ff0a, 0xd85a305dc918c262, - 0x475b1d8732225f54, 0x2d4fb51668ccb5fe, 0xa679b9d9d72bba20, 0x53841c0d912d43a5, - 0x3b7eaa48bf12a4e8, 0x781e0e47f22f1ddf, 0xeff20ce60ab50973, 0x20d261d19dffb742, - 0x16a12b03062a2e39, 0x1960eb2239650495, 0x251c16fed50eb8b8, 0x9ac0c330f826016e, - 0xed152665953e7671, 0x02d63194a6369570, 0x5074f08394b1c987, 0x70ba598c90b25ce1, - 0x794a15810b9742f6, 0x0d5925e9fcaf8c6c, 0x3067716cd868744e, 0x910ab077e8d7731b, - 0x6a61bbdb5ac42f61, 0x93513efbf0851567, 0xf494724b9e83e9d5, 0xe887e1985c09648d, - 0x34b1d3c675370cfd, 0xdc35e433bc0d255d, 0xd0aab84234131be0, 0x08042a50b48b7eaf, - 0x9997c4ee44a3ab35, 0x829a7b49201799d0, 0x263b8307b7c54441, 0x752f95f4fd6a6ca6, - 0x927217402c08c6e5, 0x2a8ab754a795d9ee, 0xa442f7552f72943d, 0x2c31334e19781208, - 0x4fa98d7ceaee6291, 0x55c3862f665db309, 0xbd0610175d53b1f3, 0x46fe6cb840413f27, - 0x3fe03792df0cfa59, 0xcfe700372eb85e8f, 0xa7be29e7adbce118, 0xe544ee5cde8431dd, - 0x8a781b1b41f1873e, 0xa5c94c78a0d2f0e7, 0x39412e2877b60728, 0xa1265ef3afc9a62c, - 0xbcc2770c6a2506c5, 0x3ab66dd5dce1ce12, 0xe65499d04a675b37, 0x7d8f523481bfd216, - 0x0f6f64fcec15f389, 0x74efbe618b5b13c8, 0xacdc82b714273e1d, 0xdd40bfe003199d17, - 0x37e99257e7e061f8, 0xfa52626904775aaa, 0x8bbbf63a463d56f9, 0xf0013f1543a26e64, - 0xa8307e9f879ec898, 0xcc4c27a4150177cc, 0x1b432f2cca1d3348, 0xde1d1f8f9f6fa013, - 0x606602a047a7ddd6, 0xd237ab64cc1cb2c7, 0x9b938e7225fcd1d3, 0xec4e03708e0ff476, - 0xfeb2fbda3d03c12d, 0xae0bced2ee43889a, 0x22cb8923ebfb4f43, 0x69360d013cf7396d, - 0x855e3602d2d4e022, 0x073805bad01f784c, 0x33e17a133852f546, 0xdf4874058ac7b638, - 0xba92b29c678aa14a, 0x0ce89fc76cfaadcd, 0x5f9d4e0908339e34, 0xf1afe9291f5923b9, - 0x6e3480f60f4a265f, 0xeebf3a2ab29b841c, 0xe21938a88f91b4ad, 0x57dfeff845c6d3c3, - 0x2f006b0bf62caaf2, 0x62f479ef6f75ee78, 0x11a55ad41c8916a9, 0xf229d29084fed453, - 0x42f1c27b16b000e6, 0x2b1f76749823c074, 0x4b76eca3c2745360, 0x8c98f463b91691bd, - 0x14bcc93cf1ade66a, 0x8885213e6d458397, 0x8e177df0274d4711, 0xb49b73b5503f2951, - 0x10168168c3f96b6b, 0x0e3d963b63cab0ae, 0x8dfc4b5655a1db14, 0xf789f1356e14de5c, - 0x683e68af4e51dac1, 0xc9a84f9d8d4b0fd9, 0x3691e03f52a0f9d1, 0x5ed86e46e1878e80, - 0x3c711a0e99d07150, 0x5a0865b20c4e9310, 0x56fbfc1fe4f0682e, 0xea8d5de3105edf9b, - 0x71abfdb12379187a, 0x2eb99de1bee77b9c, 0x21ecc0ea33cf4523, 0x59a4d7521805c7a1, - 0x3896f5eb56ae7c72, 0xaa638f3db18f75dc, 0x9f39358dabe9808e, 0xb7defa91c00b72ac, - 0x6b5541fd62492d92, 0x6dc6dee8f92e4d5b, 0x353f57abc4beea7e, 0x735769d6da5690ce, - 0x0a234aa642391484, 0xf6f9508028f80d9d, 0xb8e319a27ab3f215, 0x31ad9c1151341a4d, - 0x773c22a57bef5805, 0x45c7561a07968633, 0xf913da9e249dbe36, 0xda652d9b78a64c68, - 0x4c27a97f3bc334ef, 0x76621220e66b17f4, 0x967743899acd7d0b, 0xf3ee5bcae0ed6782, - 0x409f753600c879fc, 0x06d09a39b5926db6, 0x6f83aeb0317ac588, 0x01e6ca4a86381f21, - 0x66ff3462d19f3025, 0x72207c24ddfd3bfb, 0x4af6b6d3e2ece2eb, 0x9c994dbec7ea08de, - 0x49ace597b09a8bc4, 0xb38c4766cf0797ba, 0x131b9373c57c2a75, 0xb1822cce61931e58, - 0x9d7555b909ba1c0c, 0x127fafdd937d11d2, 0x29da3badc66d92e4, 0xa2c1d57154c2ecbc, - 0x58c5134d82f6fe24, 0x1c3ae3515b62274f, 0xe907c82e01cb8126, 0xf8ed091913e37fcb, - 0x3249d8f9c80046c9, 0x80cf9bede388fb63, 0x1881539a116cf19e, 0x5103f3f76bd52457, - 0x15b7e6f5ae47f7a8, 0xdbd7c6ded47e9ccf, 0x44e55c410228bb1a, 0xb647d4255edb4e99, - 0x5d11882bb8aafc30, 0xf5098bbb29d3212a, 0x8fb5ea14e90296b3, 0x677b942157dd025a, - 0xfb58e7c0a390acb5, 0x89d3674c83bd4a01, 0x9e2da4df4bf3b93b, 0xfcc41e328cab4829, - 0x03f38c96ba582c52, 0xcad1bdbd7fd85db2, 0xbbb442c16082ae83, 0xb95fe86ba5da9ab0, - 0xb22e04673771a93f, 0x845358c9493152d8, 0xbe2a488697b4541e, 0x95a2dc2dd38e6966, - 0xc02c11ac923c852b, 0x2388b1990df2a87b, 0x7c8008fa1b4f37be, 0x1f70d0c84d54e503, - 0x5490adec7ece57d4, 0x002b3c27d9063a3a, 0x7eaea3848030a2bf, 0xc602326ded2003c0, - 0x83a7287d69a94086, 0xc57a5fcb30f57a8a, 0xb56844e479ebe779, 0xa373b40f05dcbce9, - 0xd71a786e88570ee2, 0x879cbacdbde8f6a0, 0x976ad1bcc164a32f, 0xab21e25e9666d78b, - 0x901063aae5e5c33c, 0x9818b34448698d90, 0xe36487ae3e1e8abb, 0xafbdf931893bdcb4, - 0x6345a0dc5fbbd519, 0x8628fe269b9465ca, 0x1e5d01603f9c51ec, 0x4de44006a15049b7, - 0xbf6c70e5f776cbb1, 0x411218f2ef552bed, 0xcb0c0708705a36a3, 0xe74d14754f986044, - 0xcd56d9430ea8280e, 0xc12591d7535f5065, 0xc83223f1720aef96, 0xc3a0396f7363a51f, -} - -Tiger_Context :: struct { - a: u64, - b: u64, - c: u64, - x: [64]byte, - nx: int, - length: u64, - ver: int, -} - -round :: #force_inline proc "contextless" (a, b, c, x, mul: u64) -> (u64, u64, u64) { - a, b, c := a, b, c - c ~= x - a -= T1[c & 0xff] ~ T2[(c >> 16) & 0xff] ~ T3[(c >> 32) & 0xff] ~ T4[(c >> 48) & 0xff] - b += T4[(c >> 8) & 0xff] ~ T3[(c >> 24) & 0xff] ~ T2[(c >> 40) & 0xff] ~ T1[(c >> 56) & 0xff] - b *= mul - return a, b, c -} - -pass :: #force_inline proc "contextless" (a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) { - x, y, z = round(a, b, c, d[0], mul) - y, z, x = round(y, z, x, d[1], mul) - z, x, y = round(z, x, y, d[2], mul) - x, y, z = round(x, y, z, d[3], mul) - y, z, x = round(y, z, x, d[4], mul) - z, x, y = round(z, x, y, d[5], mul) - x, y, z = round(x, y, z, d[6], mul) - y, z, x = round(y, z, x, d[7], mul) - return -} - -key_schedule :: #force_inline proc "contextless" (x: []u64) { - x[0] -= x[7] ~ 0xa5a5a5a5a5a5a5a5 - x[1] ~= x[0] - x[2] += x[1] - x[3] -= x[2] ~ ((~x[1]) << 19) - x[4] ~= x[3] - x[5] += x[4] - x[6] -= x[5] ~ ((~x[4]) >> 23) - x[7] ~= x[6] - x[0] += x[7] - x[1] -= x[0] ~ ((~x[7]) << 19) - x[2] ~= x[1] - x[3] += x[2] - x[4] -= x[3] ~ ((~x[2]) >> 23) - x[5] ~= x[4] - x[6] += x[5] - x[7] -= x[6] ~ 0x0123456789abcdef -} - -compress :: #force_inline proc "contextless" (ctx: ^Tiger_Context, data: []byte) { - a := ctx.a - b := ctx.b - c := ctx.c - x := util.cast_slice([]u64, data) - ctx.a, ctx.b, ctx.c = pass(ctx.a, ctx.b, ctx.c, x, 5) - key_schedule(x) - ctx.c, ctx.a, ctx.b = pass(ctx.c, ctx.a, ctx.b, x, 7) - key_schedule(x) - ctx.b, ctx.c, ctx.a = pass(ctx.b, ctx.c, ctx.a, x, 9) - ctx.a ~= a - ctx.b -= b - ctx.c += c -} - -init :: proc "contextless" (ctx: ^Tiger_Context) { - ctx.a = 0x0123456789abcdef - ctx.b = 0xfedcba9876543210 - ctx.c = 0xf096a5b4c3b2e187 -} - -update :: proc(ctx: ^Tiger_Context, input: []byte) { - p := make([]byte, len(input)) - copy(p, input) - - length := len(p) - ctx.length += u64(length) - if ctx.nx > 0 { - n := len(p) - if n > 64 - ctx.nx { - n = 64 - ctx.nx - } - copy(ctx.x[ctx.nx:ctx.nx + n], p[:n]) - ctx.nx += n - if ctx.nx == 64 { - compress(ctx, ctx.x[:64 - 1]) - ctx.nx = 0 - } - p = p[n:] - } - for len(p) >= 64 { - compress(ctx, p[:64]) - p = p[64:] - } - if len(p) > 0 { - ctx.nx = copy(ctx.x[:], p) - } -} - -final :: proc(ctx: ^Tiger_Context, hash: []byte) { - length := ctx.length - tmp: [64]byte - if ctx.ver == 1 { - tmp[0] = 0x01 - } else { - tmp[0] = 0x80 - } - - size := length & 0x3f - if size < 56 { - update(ctx, tmp[:56 - size]) - } else { - update(ctx, tmp[:64 + 56 - size]) - } - - length <<= 3 - for i := uint(0); i < 8; i += 1 { - tmp[i] = byte(length >> (8 * i)) - } - update(ctx, tmp[:8]) - - for i := uint(0); i < 8; i += 1 { - tmp[i] = byte(ctx.a >> (8 * i)) - tmp[i + 8] = byte(ctx.b >> (8 * i)) - tmp[i + 16] = byte(ctx.c >> (8 * i)) - } - copy(hash[:], tmp[:len(hash)]) -} \ No newline at end of file diff --git a/core/crypto/tiger/tiger.odin b/core/crypto/tiger/tiger.odin deleted file mode 100644 index 614926129..000000000 --- a/core/crypto/tiger/tiger.odin +++ /dev/null @@ -1,280 +0,0 @@ -package tiger - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Interface for the Tiger1 variant of the Tiger hashing algorithm as defined in -*/ - -import "core:os" -import "core:io" - -import "../_tiger" - -/* - High level API -*/ - -DIGEST_SIZE_128 :: 16 -DIGEST_SIZE_160 :: 20 -DIGEST_SIZE_192 :: 24 - -// hash_string_128 will hash the given input and return the -// computed hash -hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128(transmute([]byte)(data)) -} - -// hash_bytes_128 will hash the given input and return the -// computed hash -hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_128 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_128 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash) -} - -// hash_stream_128 will read the stream in chunks and compute a -// hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _tiger.update(&ctx, buf[:read]) - } - } - _tiger.final(&ctx, hash[:]) - return hash, true -} - -// hash_file_128 will read the file provided by the given handle -// and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false -} - -hash_128 :: proc { - hash_stream_128, - hash_file_128, - hash_bytes_128, - hash_string_128, - hash_bytes_to_buffer_128, - hash_string_to_buffer_128, -} - -// hash_string_160 will hash the given input and return the -// computed hash -hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160(transmute([]byte)(data)) -} - -// hash_bytes_160 will hash the given input and return the -// computed hash -hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_160 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash) -} - -// hash_stream_160 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _tiger.update(&ctx, buf[:read]) - } - } - _tiger.final(&ctx, hash[:]) - return hash, true -} - -// hash_file_160 will read the file provided by the given handle -// and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160 :: proc { - hash_stream_160, - hash_file_160, - hash_bytes_160, - hash_string_160, - hash_bytes_to_buffer_160, - hash_string_to_buffer_160, -} - -// hash_string_192 will hash the given input and return the -// computed hash -hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte { - return hash_bytes_192(transmute([]byte)(data)) -} - -// hash_bytes_192 will hash the given input and return the -// computed hash -hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { - hash: [DIGEST_SIZE_192]byte - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_192 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_192 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_192 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash) -} - -// hash_stream_192 will read the stream in chunks and compute a -// hash from its contents -hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { - hash: [DIGEST_SIZE_192]byte - ctx: _tiger.Tiger_Context - ctx.ver = 1 - _tiger.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _tiger.update(&ctx, buf[:read]) - } - } - _tiger.final(&ctx, hash[:]) - return hash, true -} - -// hash_file_192 will read the file provided by the given handle -// and compute a hash -hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { - if !load_at_once { - return hash_stream_192(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_192(buf[:]), ok - } - } - return [DIGEST_SIZE_192]byte{}, false -} - -hash_192 :: proc { - hash_stream_192, - hash_file_192, - hash_bytes_192, - hash_string_192, - hash_bytes_to_buffer_192, - hash_string_to_buffer_192, -} - -/* - Low level API -*/ - -Tiger_Context :: _tiger.Tiger_Context - -init :: proc(ctx: ^_tiger.Tiger_Context) { - ctx.ver = 1 - _tiger.init(ctx) -} - -update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) { - _tiger.update(ctx, data) -} - -final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) { - _tiger.final(ctx, hash) -} \ No newline at end of file diff --git a/core/crypto/tiger2/tiger2.odin b/core/crypto/tiger2/tiger2.odin deleted file mode 100644 index ead874d56..000000000 --- a/core/crypto/tiger2/tiger2.odin +++ /dev/null @@ -1,280 +0,0 @@ -package tiger2 - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Interface for the Tiger2 variant of the Tiger hashing algorithm as defined in -*/ - -import "core:os" -import "core:io" - -import "../_tiger" - -/* - High level API -*/ - -DIGEST_SIZE_128 :: 16 -DIGEST_SIZE_160 :: 20 -DIGEST_SIZE_192 :: 24 - -// hash_string_128 will hash the given input and return the -// computed hash -hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128(transmute([]byte)(data)) -} - -// hash_bytes_128 will hash the given input and return the -// computed hash -hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_128 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_128 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash) -} - -// hash_stream_128 will read the stream in chunks and compute a -// hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _tiger.update(&ctx, buf[:read]) - } - } - _tiger.final(&ctx, hash[:]) - return hash, true -} - -// hash_file_128 will read the file provided by the given handle -// and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false -} - -hash_128 :: proc { - hash_stream_128, - hash_file_128, - hash_bytes_128, - hash_string_128, - hash_bytes_to_buffer_128, - hash_string_to_buffer_128, -} - -// hash_string_160 will hash the given input and return the -// computed hash -hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160(transmute([]byte)(data)) -} - -// hash_bytes_160 will hash the given input and return the -// computed hash -hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_160 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash) -} - -// hash_stream_160 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _tiger.update(&ctx, buf[:read]) - } - } - _tiger.final(&ctx, hash[:]) - return hash, true -} - -// hash_file_160 will read the file provided by the given handle -// and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160 :: proc { - hash_stream_160, - hash_file_160, - hash_bytes_160, - hash_string_160, - hash_bytes_to_buffer_160, - hash_string_to_buffer_160, -} - -// hash_string_192 will hash the given input and return the -// computed hash -hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte { - return hash_bytes_192(transmute([]byte)(data)) -} - -// hash_bytes_192 will hash the given input and return the -// computed hash -hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { - hash: [DIGEST_SIZE_192]byte - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer_192 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_192 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_192 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - _tiger.update(&ctx, data) - _tiger.final(&ctx, hash) -} - -// hash_stream_192 will read the stream in chunks and compute a -// hash from its contents -hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { - hash: [DIGEST_SIZE_192]byte - ctx: _tiger.Tiger_Context - ctx.ver = 2 - _tiger.init(&ctx) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - _tiger.update(&ctx, buf[:read]) - } - } - _tiger.final(&ctx, hash[:]) - return hash, true -} - -// hash_file_192 will read the file provided by the given handle -// and compute a hash -hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { - if !load_at_once { - return hash_stream_192(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_192(buf[:]), ok - } - } - return [DIGEST_SIZE_192]byte{}, false -} - -hash_192 :: proc { - hash_stream_192, - hash_file_192, - hash_bytes_192, - hash_string_192, - hash_bytes_to_buffer_192, - hash_string_to_buffer_192, -} - -/* - Low level API -*/ - -Tiger_Context :: _tiger.Tiger_Context - -init :: proc(ctx: ^_tiger.Tiger_Context) { - ctx.ver = 2 - _tiger.init(ctx) -} - -update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) { - _tiger.update(ctx, data) -} - -final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) { - _tiger.final(ctx, hash) -} \ No newline at end of file diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index f26672514..8c817dd82 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -35,8 +35,6 @@ import sha2 "core:crypto/sha2" import sha3 "core:crypto/sha3" import shake "core:crypto/shake" import sm3 "core:crypto/sm3" -import tiger "core:crypto/tiger" -import tiger2 "core:crypto/tiger2" import crypto_util "core:crypto/util" import whirlpool "core:crypto/whirlpool" import x25519 "core:crypto/x25519" @@ -153,8 +151,6 @@ _ :: sha2 _ :: sha3 _ :: shake _ :: sm3 -_ :: tiger -_ :: tiger2 _ :: crypto_util _ :: whirlpool _ :: x25519 diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index bcfd15609..1ae8b22d3 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -10,7 +10,6 @@ import sha3 "vendor:botan/sha3" import shake "vendor:botan/shake" import siphash "vendor:botan/siphash" import sm3 "vendor:botan/sm3" -import tiger "vendor:botan/tiger" import whirlpool "vendor:botan/whirlpool" import cgltf "vendor:cgltf" @@ -51,7 +50,6 @@ _ :: sha3 _ :: shake _ :: siphash _ :: sm3 -_ :: tiger _ :: whirlpool diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index adb2bf0d9..60410c269 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -25,8 +25,6 @@ import "core:crypto/shake" import "core:crypto/whirlpool" import "core:crypto/blake2b" import "core:crypto/blake2s" -import "core:crypto/tiger" -import "core:crypto/tiger2" import "core:crypto/sm3" import "core:crypto/siphash" import "core:os" @@ -74,12 +72,6 @@ main :: proc() { test_whirlpool(&t) test_blake2b(&t) test_blake2s(&t) - test_tiger_128(&t) - test_tiger_160(&t) - test_tiger_192(&t) - test_tiger2_128(&t) - test_tiger2_160(&t) - test_tiger2_192(&t) test_sm3(&t) test_siphash_2_4(&t) @@ -476,108 +468,6 @@ test_blake2s :: proc(t: ^testing.T) { } } -@(test) -test_tiger_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_tiger_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_tiger_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_tiger2_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b92", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_tiger2_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_tiger2_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_sm3 :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 9350486a9..897987721 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -25,7 +25,6 @@ import "vendor:botan/keccak" import "vendor:botan/shake" import "vendor:botan/whirlpool" import "vendor:botan/blake2b" -import "vendor:botan/tiger" import "vendor:botan/sm3" import "vendor:botan/siphash" @@ -69,9 +68,6 @@ main :: proc() { test_keccak_512(&t) test_whirlpool(&t) test_blake2b(&t) - // test_tiger_128(&t) - // test_tiger_160(&t) - // test_tiger_192(&t) test_sm3(&t) test_siphash_2_4(&t) @@ -383,66 +379,6 @@ test_blake2b :: proc(t: ^testing.T) { } } -@(test) -test_tiger_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_tiger_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_tiger_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_sm3 :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/vendor/botan/README.md b/vendor/botan/README.md index ec733d47a..560f207fd 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -16,7 +16,6 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | -| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | | [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | #### High level API diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index a006977c2..6b1f6ae41 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -77,9 +77,6 @@ HASH_KECCAK_512 :: "Keccak-1600" HASH_WHIRLPOOL :: "Whirlpool" HASH_BLAKE2B :: "BLAKE2b" HASH_MD5 :: "MD5" -HASH_TIGER_128 :: "Tiger(16,3)" -HASH_TIGER_160 :: "Tiger(20,3)" -HASH_TIGER_192 :: "Tiger(24,3)" HASH_SM3 :: "SM3" MAC_HMAC_SHA1 :: "HMAC(SHA1)" diff --git a/vendor/botan/tiger/tiger.odin b/vendor/botan/tiger/tiger.odin deleted file mode 100644 index 960d4694b..000000000 --- a/vendor/botan/tiger/tiger.odin +++ /dev/null @@ -1,285 +0,0 @@ -package vendor_tiger - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial implementation. - - Interface for the Tiger hashing algorithm. - The hash will be computed via bindings to the Botan crypto library -*/ - -import "core:os" -import "core:io" - -import botan "../bindings" - -/* - High level API -*/ - -DIGEST_SIZE_128 :: 16 -DIGEST_SIZE_160 :: 20 -DIGEST_SIZE_192 :: 24 - -// hash_string_128 will hash the given input and return the -// computed hash -hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { - return hash_bytes_128(transmute([]byte)(data)) -} - -// hash_bytes_128 will hash the given input and return the -// computed hash -hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { - hash: [DIGEST_SIZE_128]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_128, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_128 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_128(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_128 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_128, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_128 will read the stream in chunks and compute a -// hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { - hash: [DIGEST_SIZE_128]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_128, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_128 will read the file provided by the given handle -// and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { - if !load_at_once { - return hash_stream_128(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128(buf[:]), ok - } - } - return [DIGEST_SIZE_128]byte{}, false -} - -hash_128 :: proc { - hash_stream_128, - hash_file_128, - hash_bytes_128, - hash_string_128, - hash_bytes_to_buffer_128, - hash_string_to_buffer_128, -} - -// hash_string_160 will hash the given input and return the -// computed hash -hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { - return hash_bytes_160(transmute([]byte)(data)) -} - -// hash_bytes_160 will hash the given input and return the -// computed hash -hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { - hash: [DIGEST_SIZE_160]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_160, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_160 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_160(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_160 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_160, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_160 will read the stream in chunks and compute a -// hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { - hash: [DIGEST_SIZE_160]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_160, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_160 will read the file provided by the given handle -// and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { - if !load_at_once { - return hash_stream_160(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_160(buf[:]), ok - } - } - return [DIGEST_SIZE_160]byte{}, false -} - -hash_160 :: proc { - hash_stream_160, - hash_file_160, - hash_bytes_160, - hash_string_160, - hash_bytes_to_buffer_160, - hash_string_to_buffer_160, -} - -// hash_string_192 will hash the given input and return the -// computed hash -hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte { - return hash_bytes_192(transmute([]byte)(data)) -} - -// hash_bytes_192 will hash the given input and return the -// computed hash -hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { - hash: [DIGEST_SIZE_192]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_192, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer_192 will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer_192(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer_192 will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer_192 :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_192, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream_192 will read the stream in chunks and compute a -// hash from its contents -hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { - hash: [DIGEST_SIZE_192]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_TIGER_192, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file_192 will read the file provided by the given handle -// and compute a hash -hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { - if !load_at_once { - return hash_stream_192(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_192(buf[:]), ok - } - } - return [DIGEST_SIZE_192]byte{}, false -} - -hash_192 :: proc { - hash_stream_192, - hash_file_192, - hash_bytes_192, - hash_string_192, - hash_bytes_to_buffer_192, - hash_string_to_buffer_192, -} - -/* - Low level API -*/ - -Tiger_Context :: botan.hash_t - -init :: proc "contextless" (ctx: ^botan.hash_t, hash_size := 192) { - switch hash_size { - case 128: botan.hash_init(ctx, botan.HASH_TIGER_128, 0) - case 160: botan.hash_init(ctx, botan.HASH_TIGER_160, 0) - case 192: botan.hash_init(ctx, botan.HASH_TIGER_192, 0) - } -} - -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { - botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) -} - -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { - botan.hash_final(ctx^, &hash[0]) - botan.hash_destroy(ctx^) -} From 8af6da5de10a642c347b9d4b47261f19c9818c1b Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 22:03:33 +0900 Subject: [PATCH 100/160] core/crypto/whirlpool: Remove, historical/exotic --- core/crypto/README.md | 1 - core/crypto/whirlpool/whirlpool.odin | 806 ---------------------- examples/all/all_main.odin | 2 - examples/all/all_vendor.odin | 2 - tests/core/crypto/test_core_crypto.odin | 28 - tests/vendor/botan/test_vendor_botan.odin | 28 - vendor/botan/README.md | 1 - vendor/botan/bindings/botan.odin | 1 - vendor/botan/whirlpool/whirlpool.odin | 121 ---- 9 files changed, 990 deletions(-) delete mode 100644 core/crypto/whirlpool/whirlpool.odin delete mode 100644 vendor/botan/whirlpool/whirlpool.odin diff --git a/core/crypto/README.md b/core/crypto/README.md index 402d5605f..69f76b719 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -17,7 +17,6 @@ Please see the chart below for the options. | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | -| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | #### High level API Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*. diff --git a/core/crypto/whirlpool/whirlpool.odin b/core/crypto/whirlpool/whirlpool.odin deleted file mode 100644 index cf0bf6490..000000000 --- a/core/crypto/whirlpool/whirlpool.odin +++ /dev/null @@ -1,806 +0,0 @@ -package whirlpool - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Implementation of the Whirlpool hashing algorithm, as defined in -*/ - -import "core:os" -import "core:io" - -import "../util" - -/* - High level API -*/ - -DIGEST_SIZE :: 64 - -// hash_string will hash the given input and return the -// computed hash -hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) -} - -// hash_bytes will hash the given input and return the -// computed hash -hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: Whirlpool_Context - // init(&ctx) No-op - update(&ctx, data) - final(&ctx, hash[:]) - return hash -} - -// hash_string_to_buffer will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: Whirlpool_Context - // init(&ctx) No-op - update(&ctx, data) - final(&ctx, hash) -} - -// hash_stream will read the stream in chunks and compute a -// hash from its contents -hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: Whirlpool_Context - // init(&ctx) No-op - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = io.read(s, buf) - if read > 0 { - update(&ctx, buf[:read]) - } - } - final(&ctx, hash[:]) - return hash, true -} - -// hash_file will read the file provided by the given handle -// and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false -} - -hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, -} - -/* - Low level API -*/ - -@(warning="Init is a no-op for Whirlpool") -init :: proc(ctx: ^Whirlpool_Context) { - // No action needed here -} - -update :: proc(ctx: ^Whirlpool_Context, source: []byte) { - source_pos: int - nn := len(source) - source_bits := u64(nn * 8) - source_gap := u32((8 - (int(source_bits & 7))) & 7) - buffer_rem := uint(ctx.buffer_bits & 7) - b: u32 - - for i, carry, value := 31, u32(0), u32(source_bits); i >= 0 && (carry != 0 || value != 0); i -= 1 { - carry += u32(ctx.bitlength[i]) + (u32(value & 0xff)) - ctx.bitlength[i] = byte(carry) - carry >>= 8 - value >>= 8 - } - - for source_bits > 8 { - b = u32(u32((source[source_pos] << source_gap) & 0xff) | u32((source[source_pos+1] & 0xff) >> (8 - source_gap))) - - ctx.buffer[ctx.buffer_pos] |= u8(b >> buffer_rem) - ctx.buffer_pos += 1 - ctx.buffer_bits += int(8 - buffer_rem) - - if ctx.buffer_bits == 512 { - transform(ctx) - ctx.buffer_bits = 0 - ctx.buffer_pos = 0 - } - ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) - ctx.buffer_bits += int(buffer_rem) - source_bits -= 8 - source_pos += 1 - } - - if source_bits > 0 { - b = u32((source[source_pos] << source_gap) & 0xff) - ctx.buffer[ctx.buffer_pos] |= byte(b) >> buffer_rem - } else {b = 0} - - if u64(buffer_rem) + source_bits < 8 { - ctx.buffer_bits += int(source_bits) - } else { - ctx.buffer_pos += 1 - ctx.buffer_bits += 8 - int(buffer_rem) - source_bits -= u64(8 - buffer_rem) - - if ctx.buffer_bits == 512 { - transform(ctx) - ctx.buffer_bits = 0 - ctx.buffer_pos = 0 - } - ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) - ctx.buffer_bits += int(source_bits) - } -} - -final :: proc(ctx: ^Whirlpool_Context, hash: []byte) { - n := ctx - n.buffer[n.buffer_pos] |= 0x80 >> (uint(n.buffer_bits) & 7) - n.buffer_pos += 1 - - if n.buffer_pos > 64 - 32 { - if n.buffer_pos < 64 { - for i := 0; i < 64 - n.buffer_pos; i += 1 { - n.buffer[n.buffer_pos + i] = 0 - } - } - transform(ctx) - n.buffer_pos = 0 - } - - if n.buffer_pos < 64 - 32 { - for i := 0; i < (64 - 32) - n.buffer_pos; i += 1 { - n.buffer[n.buffer_pos + i] = 0 - } - } - n.buffer_pos = 64 - 32 - - for i := 0; i < 32; i += 1 { - n.buffer[n.buffer_pos + i] = n.bitlength[i] - } - transform(ctx) - - for i := 0; i < 8; i += 1 { - hash[i * 8] = byte(n.hash[i] >> 56) - hash[i * 8 + 1] = byte(n.hash[i] >> 48) - hash[i * 8 + 2] = byte(n.hash[i] >> 40) - hash[i * 8 + 3] = byte(n.hash[i] >> 32) - hash[i * 8 + 4] = byte(n.hash[i] >> 24) - hash[i * 8 + 5] = byte(n.hash[i] >> 16) - hash[i * 8 + 6] = byte(n.hash[i] >> 8) - hash[i * 8 + 7] = byte(n.hash[i]) - } -} - -/* - Whirlpool implementation -*/ - -ROUNDS :: 10 - -Whirlpool_Context :: struct { - bitlength: [32]byte, - buffer: [64]byte, - buffer_bits: int, - buffer_pos: int, - hash: [8]u64, -} - -C0 := [256]u64 { - 0x18186018c07830d8, 0x23238c2305af4626, 0xc6c63fc67ef991b8, 0xe8e887e8136fcdfb, - 0x878726874ca113cb, 0xb8b8dab8a9626d11, 0x0101040108050209, 0x4f4f214f426e9e0d, - 0x3636d836adee6c9b, 0xa6a6a2a6590451ff, 0xd2d26fd2debdb90c, 0xf5f5f3f5fb06f70e, - 0x7979f979ef80f296, 0x6f6fa16f5fcede30, 0x91917e91fcef3f6d, 0x52525552aa07a4f8, - 0x60609d6027fdc047, 0xbcbccabc89766535, 0x9b9b569baccd2b37, 0x8e8e028e048c018a, - 0xa3a3b6a371155bd2, 0x0c0c300c603c186c, 0x7b7bf17bff8af684, 0x3535d435b5e16a80, - 0x1d1d741de8693af5, 0xe0e0a7e05347ddb3, 0xd7d77bd7f6acb321, 0xc2c22fc25eed999c, - 0x2e2eb82e6d965c43, 0x4b4b314b627a9629, 0xfefedffea321e15d, 0x575741578216aed5, - 0x15155415a8412abd, 0x7777c1779fb6eee8, 0x3737dc37a5eb6e92, 0xe5e5b3e57b56d79e, - 0x9f9f469f8cd92313, 0xf0f0e7f0d317fd23, 0x4a4a354a6a7f9420, 0xdada4fda9e95a944, - 0x58587d58fa25b0a2, 0xc9c903c906ca8fcf, 0x2929a429558d527c, 0x0a0a280a5022145a, - 0xb1b1feb1e14f7f50, 0xa0a0baa0691a5dc9, 0x6b6bb16b7fdad614, 0x85852e855cab17d9, - 0xbdbdcebd8173673c, 0x5d5d695dd234ba8f, 0x1010401080502090, 0xf4f4f7f4f303f507, - 0xcbcb0bcb16c08bdd, 0x3e3ef83eedc67cd3, 0x0505140528110a2d, 0x676781671fe6ce78, - 0xe4e4b7e47353d597, 0x27279c2725bb4e02, 0x4141194132588273, 0x8b8b168b2c9d0ba7, - 0xa7a7a6a7510153f6, 0x7d7de97dcf94fab2, 0x95956e95dcfb3749, 0xd8d847d88e9fad56, - 0xfbfbcbfb8b30eb70, 0xeeee9fee2371c1cd, 0x7c7ced7cc791f8bb, 0x6666856617e3cc71, - 0xdddd53dda68ea77b, 0x17175c17b84b2eaf, 0x4747014702468e45, 0x9e9e429e84dc211a, - 0xcaca0fca1ec589d4, 0x2d2db42d75995a58, 0xbfbfc6bf9179632e, 0x07071c07381b0e3f, - 0xadad8ead012347ac, 0x5a5a755aea2fb4b0, 0x838336836cb51bef, 0x3333cc3385ff66b6, - 0x636391633ff2c65c, 0x02020802100a0412, 0xaaaa92aa39384993, 0x7171d971afa8e2de, - 0xc8c807c80ecf8dc6, 0x19196419c87d32d1, 0x494939497270923b, 0xd9d943d9869aaf5f, - 0xf2f2eff2c31df931, 0xe3e3abe34b48dba8, 0x5b5b715be22ab6b9, 0x88881a8834920dbc, - 0x9a9a529aa4c8293e, 0x262698262dbe4c0b, 0x3232c8328dfa64bf, 0xb0b0fab0e94a7d59, - 0xe9e983e91b6acff2, 0x0f0f3c0f78331e77, 0xd5d573d5e6a6b733, 0x80803a8074ba1df4, - 0xbebec2be997c6127, 0xcdcd13cd26de87eb, 0x3434d034bde46889, 0x48483d487a759032, - 0xffffdbffab24e354, 0x7a7af57af78ff48d, 0x90907a90f4ea3d64, 0x5f5f615fc23ebe9d, - 0x202080201da0403d, 0x6868bd6867d5d00f, 0x1a1a681ad07234ca, 0xaeae82ae192c41b7, - 0xb4b4eab4c95e757d, 0x54544d549a19a8ce, 0x93937693ece53b7f, 0x222288220daa442f, - 0x64648d6407e9c863, 0xf1f1e3f1db12ff2a, 0x7373d173bfa2e6cc, 0x12124812905a2482, - 0x40401d403a5d807a, 0x0808200840281048, 0xc3c32bc356e89b95, 0xecec97ec337bc5df, - 0xdbdb4bdb9690ab4d, 0xa1a1bea1611f5fc0, 0x8d8d0e8d1c830791, 0x3d3df43df5c97ac8, - 0x97976697ccf1335b, 0x0000000000000000, 0xcfcf1bcf36d483f9, 0x2b2bac2b4587566e, - 0x7676c57697b3ece1, 0x8282328264b019e6, 0xd6d67fd6fea9b128, 0x1b1b6c1bd87736c3, - 0xb5b5eeb5c15b7774, 0xafaf86af112943be, 0x6a6ab56a77dfd41d, 0x50505d50ba0da0ea, - 0x45450945124c8a57, 0xf3f3ebf3cb18fb38, 0x3030c0309df060ad, 0xefef9bef2b74c3c4, - 0x3f3ffc3fe5c37eda, 0x55554955921caac7, 0xa2a2b2a2791059db, 0xeaea8fea0365c9e9, - 0x656589650fecca6a, 0xbabad2bab9686903, 0x2f2fbc2f65935e4a, 0xc0c027c04ee79d8e, - 0xdede5fdebe81a160, 0x1c1c701ce06c38fc, 0xfdfdd3fdbb2ee746, 0x4d4d294d52649a1f, - 0x92927292e4e03976, 0x7575c9758fbceafa, 0x06061806301e0c36, 0x8a8a128a249809ae, - 0xb2b2f2b2f940794b, 0xe6e6bfe66359d185, 0x0e0e380e70361c7e, 0x1f1f7c1ff8633ee7, - 0x6262956237f7c455, 0xd4d477d4eea3b53a, 0xa8a89aa829324d81, 0x96966296c4f43152, - 0xf9f9c3f99b3aef62, 0xc5c533c566f697a3, 0x2525942535b14a10, 0x59597959f220b2ab, - 0x84842a8454ae15d0, 0x7272d572b7a7e4c5, 0x3939e439d5dd72ec, 0x4c4c2d4c5a619816, - 0x5e5e655eca3bbc94, 0x7878fd78e785f09f, 0x3838e038ddd870e5, 0x8c8c0a8c14860598, - 0xd1d163d1c6b2bf17, 0xa5a5aea5410b57e4, 0xe2e2afe2434dd9a1, 0x616199612ff8c24e, - 0xb3b3f6b3f1457b42, 0x2121842115a54234, 0x9c9c4a9c94d62508, 0x1e1e781ef0663cee, - 0x4343114322528661, 0xc7c73bc776fc93b1, 0xfcfcd7fcb32be54f, 0x0404100420140824, - 0x51515951b208a2e3, 0x99995e99bcc72f25, 0x6d6da96d4fc4da22, 0x0d0d340d68391a65, - 0xfafacffa8335e979, 0xdfdf5bdfb684a369, 0x7e7ee57ed79bfca9, 0x242490243db44819, - 0x3b3bec3bc5d776fe, 0xabab96ab313d4b9a, 0xcece1fce3ed181f0, 0x1111441188552299, - 0x8f8f068f0c890383, 0x4e4e254e4a6b9c04, 0xb7b7e6b7d1517366, 0xebeb8beb0b60cbe0, - 0x3c3cf03cfdcc78c1, 0x81813e817cbf1ffd, 0x94946a94d4fe3540, 0xf7f7fbf7eb0cf31c, - 0xb9b9deb9a1676f18, 0x13134c13985f268b, 0x2c2cb02c7d9c5851, 0xd3d36bd3d6b8bb05, - 0xe7e7bbe76b5cd38c, 0x6e6ea56e57cbdc39, 0xc4c437c46ef395aa, 0x03030c03180f061b, - 0x565645568a13acdc, 0x44440d441a49885e, 0x7f7fe17fdf9efea0, 0xa9a99ea921374f88, - 0x2a2aa82a4d825467, 0xbbbbd6bbb16d6b0a, 0xc1c123c146e29f87, 0x53535153a202a6f1, - 0xdcdc57dcae8ba572, 0x0b0b2c0b58271653, 0x9d9d4e9d9cd32701, 0x6c6cad6c47c1d82b, - 0x3131c43195f562a4, 0x7474cd7487b9e8f3, 0xf6f6fff6e309f115, 0x464605460a438c4c, - 0xacac8aac092645a5, 0x89891e893c970fb5, 0x14145014a04428b4, 0xe1e1a3e15b42dfba, - 0x16165816b04e2ca6, 0x3a3ae83acdd274f7, 0x6969b9696fd0d206, 0x09092409482d1241, - 0x7070dd70a7ade0d7, 0xb6b6e2b6d954716f, 0xd0d067d0ceb7bd1e, 0xeded93ed3b7ec7d6, - 0xcccc17cc2edb85e2, 0x424215422a578468, 0x98985a98b4c22d2c, 0xa4a4aaa4490e55ed, - 0x2828a0285d885075, 0x5c5c6d5cda31b886, 0xf8f8c7f8933fed6b, 0x8686228644a411c2, -} - -C1 := [256]u64 { - 0xd818186018c07830, 0x2623238c2305af46, 0xb8c6c63fc67ef991, 0xfbe8e887e8136fcd, - 0xcb878726874ca113, 0x11b8b8dab8a9626d, 0x0901010401080502, 0x0d4f4f214f426e9e, - 0x9b3636d836adee6c, 0xffa6a6a2a6590451, 0x0cd2d26fd2debdb9, 0x0ef5f5f3f5fb06f7, - 0x967979f979ef80f2, 0x306f6fa16f5fcede, 0x6d91917e91fcef3f, 0xf852525552aa07a4, - 0x4760609d6027fdc0, 0x35bcbccabc897665, 0x379b9b569baccd2b, 0x8a8e8e028e048c01, - 0xd2a3a3b6a371155b, 0x6c0c0c300c603c18, 0x847b7bf17bff8af6, 0x803535d435b5e16a, - 0xf51d1d741de8693a, 0xb3e0e0a7e05347dd, 0x21d7d77bd7f6acb3, 0x9cc2c22fc25eed99, - 0x432e2eb82e6d965c, 0x294b4b314b627a96, 0x5dfefedffea321e1, 0xd5575741578216ae, - 0xbd15155415a8412a, 0xe87777c1779fb6ee, 0x923737dc37a5eb6e, 0x9ee5e5b3e57b56d7, - 0x139f9f469f8cd923, 0x23f0f0e7f0d317fd, 0x204a4a354a6a7f94, 0x44dada4fda9e95a9, - 0xa258587d58fa25b0, 0xcfc9c903c906ca8f, 0x7c2929a429558d52, 0x5a0a0a280a502214, - 0x50b1b1feb1e14f7f, 0xc9a0a0baa0691a5d, 0x146b6bb16b7fdad6, 0xd985852e855cab17, - 0x3cbdbdcebd817367, 0x8f5d5d695dd234ba, 0x9010104010805020, 0x07f4f4f7f4f303f5, - 0xddcbcb0bcb16c08b, 0xd33e3ef83eedc67c, 0x2d0505140528110a, 0x78676781671fe6ce, - 0x97e4e4b7e47353d5, 0x0227279c2725bb4e, 0x7341411941325882, 0xa78b8b168b2c9d0b, - 0xf6a7a7a6a7510153, 0xb27d7de97dcf94fa, 0x4995956e95dcfb37, 0x56d8d847d88e9fad, - 0x70fbfbcbfb8b30eb, 0xcdeeee9fee2371c1, 0xbb7c7ced7cc791f8, 0x716666856617e3cc, - 0x7bdddd53dda68ea7, 0xaf17175c17b84b2e, 0x454747014702468e, 0x1a9e9e429e84dc21, - 0xd4caca0fca1ec589, 0x582d2db42d75995a, 0x2ebfbfc6bf917963, 0x3f07071c07381b0e, - 0xacadad8ead012347, 0xb05a5a755aea2fb4, 0xef838336836cb51b, 0xb63333cc3385ff66, - 0x5c636391633ff2c6, 0x1202020802100a04, 0x93aaaa92aa393849, 0xde7171d971afa8e2, - 0xc6c8c807c80ecf8d, 0xd119196419c87d32, 0x3b49493949727092, 0x5fd9d943d9869aaf, - 0x31f2f2eff2c31df9, 0xa8e3e3abe34b48db, 0xb95b5b715be22ab6, 0xbc88881a8834920d, - 0x3e9a9a529aa4c829, 0x0b262698262dbe4c, 0xbf3232c8328dfa64, 0x59b0b0fab0e94a7d, - 0xf2e9e983e91b6acf, 0x770f0f3c0f78331e, 0x33d5d573d5e6a6b7, 0xf480803a8074ba1d, - 0x27bebec2be997c61, 0xebcdcd13cd26de87, 0x893434d034bde468, 0x3248483d487a7590, - 0x54ffffdbffab24e3, 0x8d7a7af57af78ff4, 0x6490907a90f4ea3d, 0x9d5f5f615fc23ebe, - 0x3d202080201da040, 0x0f6868bd6867d5d0, 0xca1a1a681ad07234, 0xb7aeae82ae192c41, - 0x7db4b4eab4c95e75, 0xce54544d549a19a8, 0x7f93937693ece53b, 0x2f222288220daa44, - 0x6364648d6407e9c8, 0x2af1f1e3f1db12ff, 0xcc7373d173bfa2e6, 0x8212124812905a24, - 0x7a40401d403a5d80, 0x4808082008402810, 0x95c3c32bc356e89b, 0xdfecec97ec337bc5, - 0x4ddbdb4bdb9690ab, 0xc0a1a1bea1611f5f, 0x918d8d0e8d1c8307, 0xc83d3df43df5c97a, - 0x5b97976697ccf133, 0x0000000000000000, 0xf9cfcf1bcf36d483, 0x6e2b2bac2b458756, - 0xe17676c57697b3ec, 0xe68282328264b019, 0x28d6d67fd6fea9b1, 0xc31b1b6c1bd87736, - 0x74b5b5eeb5c15b77, 0xbeafaf86af112943, 0x1d6a6ab56a77dfd4, 0xea50505d50ba0da0, - 0x5745450945124c8a, 0x38f3f3ebf3cb18fb, 0xad3030c0309df060, 0xc4efef9bef2b74c3, - 0xda3f3ffc3fe5c37e, 0xc755554955921caa, 0xdba2a2b2a2791059, 0xe9eaea8fea0365c9, - 0x6a656589650fecca, 0x03babad2bab96869, 0x4a2f2fbc2f65935e, 0x8ec0c027c04ee79d, - 0x60dede5fdebe81a1, 0xfc1c1c701ce06c38, 0x46fdfdd3fdbb2ee7, 0x1f4d4d294d52649a, - 0x7692927292e4e039, 0xfa7575c9758fbcea, 0x3606061806301e0c, 0xae8a8a128a249809, - 0x4bb2b2f2b2f94079, 0x85e6e6bfe66359d1, 0x7e0e0e380e70361c, 0xe71f1f7c1ff8633e, - 0x556262956237f7c4, 0x3ad4d477d4eea3b5, 0x81a8a89aa829324d, 0x5296966296c4f431, - 0x62f9f9c3f99b3aef, 0xa3c5c533c566f697, 0x102525942535b14a, 0xab59597959f220b2, - 0xd084842a8454ae15, 0xc57272d572b7a7e4, 0xec3939e439d5dd72, 0x164c4c2d4c5a6198, - 0x945e5e655eca3bbc, 0x9f7878fd78e785f0, 0xe53838e038ddd870, 0x988c8c0a8c148605, - 0x17d1d163d1c6b2bf, 0xe4a5a5aea5410b57, 0xa1e2e2afe2434dd9, 0x4e616199612ff8c2, - 0x42b3b3f6b3f1457b, 0x342121842115a542, 0x089c9c4a9c94d625, 0xee1e1e781ef0663c, - 0x6143431143225286, 0xb1c7c73bc776fc93, 0x4ffcfcd7fcb32be5, 0x2404041004201408, - 0xe351515951b208a2, 0x2599995e99bcc72f, 0x226d6da96d4fc4da, 0x650d0d340d68391a, - 0x79fafacffa8335e9, 0x69dfdf5bdfb684a3, 0xa97e7ee57ed79bfc, 0x19242490243db448, - 0xfe3b3bec3bc5d776, 0x9aabab96ab313d4b, 0xf0cece1fce3ed181, 0x9911114411885522, - 0x838f8f068f0c8903, 0x044e4e254e4a6b9c, 0x66b7b7e6b7d15173, 0xe0ebeb8beb0b60cb, - 0xc13c3cf03cfdcc78, 0xfd81813e817cbf1f, 0x4094946a94d4fe35, 0x1cf7f7fbf7eb0cf3, - 0x18b9b9deb9a1676f, 0x8b13134c13985f26, 0x512c2cb02c7d9c58, 0x05d3d36bd3d6b8bb, - 0x8ce7e7bbe76b5cd3, 0x396e6ea56e57cbdc, 0xaac4c437c46ef395, 0x1b03030c03180f06, - 0xdc565645568a13ac, 0x5e44440d441a4988, 0xa07f7fe17fdf9efe, 0x88a9a99ea921374f, - 0x672a2aa82a4d8254, 0x0abbbbd6bbb16d6b, 0x87c1c123c146e29f, 0xf153535153a202a6, - 0x72dcdc57dcae8ba5, 0x530b0b2c0b582716, 0x019d9d4e9d9cd327, 0x2b6c6cad6c47c1d8, - 0xa43131c43195f562, 0xf37474cd7487b9e8, 0x15f6f6fff6e309f1, 0x4c464605460a438c, - 0xa5acac8aac092645, 0xb589891e893c970f, 0xb414145014a04428, 0xbae1e1a3e15b42df, - 0xa616165816b04e2c, 0xf73a3ae83acdd274, 0x066969b9696fd0d2, 0x4109092409482d12, - 0xd77070dd70a7ade0, 0x6fb6b6e2b6d95471, 0x1ed0d067d0ceb7bd, 0xd6eded93ed3b7ec7, - 0xe2cccc17cc2edb85, 0x68424215422a5784, 0x2c98985a98b4c22d, 0xeda4a4aaa4490e55, - 0x752828a0285d8850, 0x865c5c6d5cda31b8, 0x6bf8f8c7f8933fed, 0xc28686228644a411, -} - -C2 := [256]u64 { - 0x30d818186018c078, 0x462623238c2305af, 0x91b8c6c63fc67ef9, 0xcdfbe8e887e8136f, - 0x13cb878726874ca1, 0x6d11b8b8dab8a962, 0x0209010104010805, 0x9e0d4f4f214f426e, - 0x6c9b3636d836adee, 0x51ffa6a6a2a65904, 0xb90cd2d26fd2debd, 0xf70ef5f5f3f5fb06, - 0xf2967979f979ef80, 0xde306f6fa16f5fce, 0x3f6d91917e91fcef, 0xa4f852525552aa07, - 0xc04760609d6027fd, 0x6535bcbccabc8976, 0x2b379b9b569baccd, 0x018a8e8e028e048c, - 0x5bd2a3a3b6a37115, 0x186c0c0c300c603c, 0xf6847b7bf17bff8a, 0x6a803535d435b5e1, - 0x3af51d1d741de869, 0xddb3e0e0a7e05347, 0xb321d7d77bd7f6ac, 0x999cc2c22fc25eed, - 0x5c432e2eb82e6d96, 0x96294b4b314b627a, 0xe15dfefedffea321, 0xaed5575741578216, - 0x2abd15155415a841, 0xeee87777c1779fb6, 0x6e923737dc37a5eb, 0xd79ee5e5b3e57b56, - 0x23139f9f469f8cd9, 0xfd23f0f0e7f0d317, 0x94204a4a354a6a7f, 0xa944dada4fda9e95, - 0xb0a258587d58fa25, 0x8fcfc9c903c906ca, 0x527c2929a429558d, 0x145a0a0a280a5022, - 0x7f50b1b1feb1e14f, 0x5dc9a0a0baa0691a, 0xd6146b6bb16b7fda, 0x17d985852e855cab, - 0x673cbdbdcebd8173, 0xba8f5d5d695dd234, 0x2090101040108050, 0xf507f4f4f7f4f303, - 0x8bddcbcb0bcb16c0, 0x7cd33e3ef83eedc6, 0x0a2d050514052811, 0xce78676781671fe6, - 0xd597e4e4b7e47353, 0x4e0227279c2725bb, 0x8273414119413258, 0x0ba78b8b168b2c9d, - 0x53f6a7a7a6a75101, 0xfab27d7de97dcf94, 0x374995956e95dcfb, 0xad56d8d847d88e9f, - 0xeb70fbfbcbfb8b30, 0xc1cdeeee9fee2371, 0xf8bb7c7ced7cc791, 0xcc716666856617e3, - 0xa77bdddd53dda68e, 0x2eaf17175c17b84b, 0x8e45474701470246, 0x211a9e9e429e84dc, - 0x89d4caca0fca1ec5, 0x5a582d2db42d7599, 0x632ebfbfc6bf9179, 0x0e3f07071c07381b, - 0x47acadad8ead0123, 0xb4b05a5a755aea2f, 0x1bef838336836cb5, 0x66b63333cc3385ff, - 0xc65c636391633ff2, 0x041202020802100a, 0x4993aaaa92aa3938, 0xe2de7171d971afa8, - 0x8dc6c8c807c80ecf, 0x32d119196419c87d, 0x923b494939497270, 0xaf5fd9d943d9869a, - 0xf931f2f2eff2c31d, 0xdba8e3e3abe34b48, 0xb6b95b5b715be22a, 0x0dbc88881a883492, - 0x293e9a9a529aa4c8, 0x4c0b262698262dbe, 0x64bf3232c8328dfa, 0x7d59b0b0fab0e94a, - 0xcff2e9e983e91b6a, 0x1e770f0f3c0f7833, 0xb733d5d573d5e6a6, 0x1df480803a8074ba, - 0x6127bebec2be997c, 0x87ebcdcd13cd26de, 0x68893434d034bde4, 0x903248483d487a75, - 0xe354ffffdbffab24, 0xf48d7a7af57af78f, 0x3d6490907a90f4ea, 0xbe9d5f5f615fc23e, - 0x403d202080201da0, 0xd00f6868bd6867d5, 0x34ca1a1a681ad072, 0x41b7aeae82ae192c, - 0x757db4b4eab4c95e, 0xa8ce54544d549a19, 0x3b7f93937693ece5, 0x442f222288220daa, - 0xc86364648d6407e9, 0xff2af1f1e3f1db12, 0xe6cc7373d173bfa2, 0x248212124812905a, - 0x807a40401d403a5d, 0x1048080820084028, 0x9b95c3c32bc356e8, 0xc5dfecec97ec337b, - 0xab4ddbdb4bdb9690, 0x5fc0a1a1bea1611f, 0x07918d8d0e8d1c83, 0x7ac83d3df43df5c9, - 0x335b97976697ccf1, 0x0000000000000000, 0x83f9cfcf1bcf36d4, 0x566e2b2bac2b4587, - 0xece17676c57697b3, 0x19e68282328264b0, 0xb128d6d67fd6fea9, 0x36c31b1b6c1bd877, - 0x7774b5b5eeb5c15b, 0x43beafaf86af1129, 0xd41d6a6ab56a77df, 0xa0ea50505d50ba0d, - 0x8a5745450945124c, 0xfb38f3f3ebf3cb18, 0x60ad3030c0309df0, 0xc3c4efef9bef2b74, - 0x7eda3f3ffc3fe5c3, 0xaac755554955921c, 0x59dba2a2b2a27910, 0xc9e9eaea8fea0365, - 0xca6a656589650fec, 0x6903babad2bab968, 0x5e4a2f2fbc2f6593, 0x9d8ec0c027c04ee7, - 0xa160dede5fdebe81, 0x38fc1c1c701ce06c, 0xe746fdfdd3fdbb2e, 0x9a1f4d4d294d5264, - 0x397692927292e4e0, 0xeafa7575c9758fbc, 0x0c3606061806301e, 0x09ae8a8a128a2498, - 0x794bb2b2f2b2f940, 0xd185e6e6bfe66359, 0x1c7e0e0e380e7036, 0x3ee71f1f7c1ff863, - 0xc4556262956237f7, 0xb53ad4d477d4eea3, 0x4d81a8a89aa82932, 0x315296966296c4f4, - 0xef62f9f9c3f99b3a, 0x97a3c5c533c566f6, 0x4a102525942535b1, 0xb2ab59597959f220, - 0x15d084842a8454ae, 0xe4c57272d572b7a7, 0x72ec3939e439d5dd, 0x98164c4c2d4c5a61, - 0xbc945e5e655eca3b, 0xf09f7878fd78e785, 0x70e53838e038ddd8, 0x05988c8c0a8c1486, - 0xbf17d1d163d1c6b2, 0x57e4a5a5aea5410b, 0xd9a1e2e2afe2434d, 0xc24e616199612ff8, - 0x7b42b3b3f6b3f145, 0x42342121842115a5, 0x25089c9c4a9c94d6, 0x3cee1e1e781ef066, - 0x8661434311432252, 0x93b1c7c73bc776fc, 0xe54ffcfcd7fcb32b, 0x0824040410042014, - 0xa2e351515951b208, 0x2f2599995e99bcc7, 0xda226d6da96d4fc4, 0x1a650d0d340d6839, - 0xe979fafacffa8335, 0xa369dfdf5bdfb684, 0xfca97e7ee57ed79b, 0x4819242490243db4, - 0x76fe3b3bec3bc5d7, 0x4b9aabab96ab313d, 0x81f0cece1fce3ed1, 0x2299111144118855, - 0x03838f8f068f0c89, 0x9c044e4e254e4a6b, 0x7366b7b7e6b7d151, 0xcbe0ebeb8beb0b60, - 0x78c13c3cf03cfdcc, 0x1ffd81813e817cbf, 0x354094946a94d4fe, 0xf31cf7f7fbf7eb0c, - 0x6f18b9b9deb9a167, 0x268b13134c13985f, 0x58512c2cb02c7d9c, 0xbb05d3d36bd3d6b8, - 0xd38ce7e7bbe76b5c, 0xdc396e6ea56e57cb, 0x95aac4c437c46ef3, 0x061b03030c03180f, - 0xacdc565645568a13, 0x885e44440d441a49, 0xfea07f7fe17fdf9e, 0x4f88a9a99ea92137, - 0x54672a2aa82a4d82, 0x6b0abbbbd6bbb16d, 0x9f87c1c123c146e2, 0xa6f153535153a202, - 0xa572dcdc57dcae8b, 0x16530b0b2c0b5827, 0x27019d9d4e9d9cd3, 0xd82b6c6cad6c47c1, - 0x62a43131c43195f5, 0xe8f37474cd7487b9, 0xf115f6f6fff6e309, 0x8c4c464605460a43, - 0x45a5acac8aac0926, 0x0fb589891e893c97, 0x28b414145014a044, 0xdfbae1e1a3e15b42, - 0x2ca616165816b04e, 0x74f73a3ae83acdd2, 0xd2066969b9696fd0, 0x124109092409482d, - 0xe0d77070dd70a7ad, 0x716fb6b6e2b6d954, 0xbd1ed0d067d0ceb7, 0xc7d6eded93ed3b7e, - 0x85e2cccc17cc2edb, 0x8468424215422a57, 0x2d2c98985a98b4c2, 0x55eda4a4aaa4490e, - 0x50752828a0285d88, 0xb8865c5c6d5cda31, 0xed6bf8f8c7f8933f, 0x11c28686228644a4, -} - -C3 := [256]u64 { - 0x7830d818186018c0, 0xaf462623238c2305, 0xf991b8c6c63fc67e, 0x6fcdfbe8e887e813, - 0xa113cb878726874c, 0x626d11b8b8dab8a9, 0x0502090101040108, 0x6e9e0d4f4f214f42, - 0xee6c9b3636d836ad, 0x0451ffa6a6a2a659, 0xbdb90cd2d26fd2de, 0x06f70ef5f5f3f5fb, - 0x80f2967979f979ef, 0xcede306f6fa16f5f, 0xef3f6d91917e91fc, 0x07a4f852525552aa, - 0xfdc04760609d6027, 0x766535bcbccabc89, 0xcd2b379b9b569bac, 0x8c018a8e8e028e04, - 0x155bd2a3a3b6a371, 0x3c186c0c0c300c60, 0x8af6847b7bf17bff, 0xe16a803535d435b5, - 0x693af51d1d741de8, 0x47ddb3e0e0a7e053, 0xacb321d7d77bd7f6, 0xed999cc2c22fc25e, - 0x965c432e2eb82e6d, 0x7a96294b4b314b62, 0x21e15dfefedffea3, 0x16aed55757415782, - 0x412abd15155415a8, 0xb6eee87777c1779f, 0xeb6e923737dc37a5, 0x56d79ee5e5b3e57b, - 0xd923139f9f469f8c, 0x17fd23f0f0e7f0d3, 0x7f94204a4a354a6a, 0x95a944dada4fda9e, - 0x25b0a258587d58fa, 0xca8fcfc9c903c906, 0x8d527c2929a42955, 0x22145a0a0a280a50, - 0x4f7f50b1b1feb1e1, 0x1a5dc9a0a0baa069, 0xdad6146b6bb16b7f, 0xab17d985852e855c, - 0x73673cbdbdcebd81, 0x34ba8f5d5d695dd2, 0x5020901010401080, 0x03f507f4f4f7f4f3, - 0xc08bddcbcb0bcb16, 0xc67cd33e3ef83eed, 0x110a2d0505140528, 0xe6ce78676781671f, - 0x53d597e4e4b7e473, 0xbb4e0227279c2725, 0x5882734141194132, 0x9d0ba78b8b168b2c, - 0x0153f6a7a7a6a751, 0x94fab27d7de97dcf, 0xfb374995956e95dc, 0x9fad56d8d847d88e, - 0x30eb70fbfbcbfb8b, 0x71c1cdeeee9fee23, 0x91f8bb7c7ced7cc7, 0xe3cc716666856617, - 0x8ea77bdddd53dda6, 0x4b2eaf17175c17b8, 0x468e454747014702, 0xdc211a9e9e429e84, - 0xc589d4caca0fca1e, 0x995a582d2db42d75, 0x79632ebfbfc6bf91, 0x1b0e3f07071c0738, - 0x2347acadad8ead01, 0x2fb4b05a5a755aea, 0xb51bef838336836c, 0xff66b63333cc3385, - 0xf2c65c636391633f, 0x0a04120202080210, 0x384993aaaa92aa39, 0xa8e2de7171d971af, - 0xcf8dc6c8c807c80e, 0x7d32d119196419c8, 0x70923b4949394972, 0x9aaf5fd9d943d986, - 0x1df931f2f2eff2c3, 0x48dba8e3e3abe34b, 0x2ab6b95b5b715be2, 0x920dbc88881a8834, - 0xc8293e9a9a529aa4, 0xbe4c0b262698262d, 0xfa64bf3232c8328d, 0x4a7d59b0b0fab0e9, - 0x6acff2e9e983e91b, 0x331e770f0f3c0f78, 0xa6b733d5d573d5e6, 0xba1df480803a8074, - 0x7c6127bebec2be99, 0xde87ebcdcd13cd26, 0xe468893434d034bd, 0x75903248483d487a, - 0x24e354ffffdbffab, 0x8ff48d7a7af57af7, 0xea3d6490907a90f4, 0x3ebe9d5f5f615fc2, - 0xa0403d202080201d, 0xd5d00f6868bd6867, 0x7234ca1a1a681ad0, 0x2c41b7aeae82ae19, - 0x5e757db4b4eab4c9, 0x19a8ce54544d549a, 0xe53b7f93937693ec, 0xaa442f222288220d, - 0xe9c86364648d6407, 0x12ff2af1f1e3f1db, 0xa2e6cc7373d173bf, 0x5a24821212481290, - 0x5d807a40401d403a, 0x2810480808200840, 0xe89b95c3c32bc356, 0x7bc5dfecec97ec33, - 0x90ab4ddbdb4bdb96, 0x1f5fc0a1a1bea161, 0x8307918d8d0e8d1c, 0xc97ac83d3df43df5, - 0xf1335b97976697cc, 0x0000000000000000, 0xd483f9cfcf1bcf36, 0x87566e2b2bac2b45, - 0xb3ece17676c57697, 0xb019e68282328264, 0xa9b128d6d67fd6fe, 0x7736c31b1b6c1bd8, - 0x5b7774b5b5eeb5c1, 0x2943beafaf86af11, 0xdfd41d6a6ab56a77, 0x0da0ea50505d50ba, - 0x4c8a574545094512, 0x18fb38f3f3ebf3cb, 0xf060ad3030c0309d, 0x74c3c4efef9bef2b, - 0xc37eda3f3ffc3fe5, 0x1caac75555495592, 0x1059dba2a2b2a279, 0x65c9e9eaea8fea03, - 0xecca6a656589650f, 0x686903babad2bab9, 0x935e4a2f2fbc2f65, 0xe79d8ec0c027c04e, - 0x81a160dede5fdebe, 0x6c38fc1c1c701ce0, 0x2ee746fdfdd3fdbb, 0x649a1f4d4d294d52, - 0xe0397692927292e4, 0xbceafa7575c9758f, 0x1e0c360606180630, 0x9809ae8a8a128a24, - 0x40794bb2b2f2b2f9, 0x59d185e6e6bfe663, 0x361c7e0e0e380e70, 0x633ee71f1f7c1ff8, - 0xf7c4556262956237, 0xa3b53ad4d477d4ee, 0x324d81a8a89aa829, 0xf4315296966296c4, - 0x3aef62f9f9c3f99b, 0xf697a3c5c533c566, 0xb14a102525942535, 0x20b2ab59597959f2, - 0xae15d084842a8454, 0xa7e4c57272d572b7, 0xdd72ec3939e439d5, 0x6198164c4c2d4c5a, - 0x3bbc945e5e655eca, 0x85f09f7878fd78e7, 0xd870e53838e038dd, 0x8605988c8c0a8c14, - 0xb2bf17d1d163d1c6, 0x0b57e4a5a5aea541, 0x4dd9a1e2e2afe243, 0xf8c24e616199612f, - 0x457b42b3b3f6b3f1, 0xa542342121842115, 0xd625089c9c4a9c94, 0x663cee1e1e781ef0, - 0x5286614343114322, 0xfc93b1c7c73bc776, 0x2be54ffcfcd7fcb3, 0x1408240404100420, - 0x08a2e351515951b2, 0xc72f2599995e99bc, 0xc4da226d6da96d4f, 0x391a650d0d340d68, - 0x35e979fafacffa83, 0x84a369dfdf5bdfb6, 0x9bfca97e7ee57ed7, 0xb44819242490243d, - 0xd776fe3b3bec3bc5, 0x3d4b9aabab96ab31, 0xd181f0cece1fce3e, 0x5522991111441188, - 0x8903838f8f068f0c, 0x6b9c044e4e254e4a, 0x517366b7b7e6b7d1, 0x60cbe0ebeb8beb0b, - 0xcc78c13c3cf03cfd, 0xbf1ffd81813e817c, 0xfe354094946a94d4, 0x0cf31cf7f7fbf7eb, - 0x676f18b9b9deb9a1, 0x5f268b13134c1398, 0x9c58512c2cb02c7d, 0xb8bb05d3d36bd3d6, - 0x5cd38ce7e7bbe76b, 0xcbdc396e6ea56e57, 0xf395aac4c437c46e, 0x0f061b03030c0318, - 0x13acdc565645568a, 0x49885e44440d441a, 0x9efea07f7fe17fdf, 0x374f88a9a99ea921, - 0x8254672a2aa82a4d, 0x6d6b0abbbbd6bbb1, 0xe29f87c1c123c146, 0x02a6f153535153a2, - 0x8ba572dcdc57dcae, 0x2716530b0b2c0b58, 0xd327019d9d4e9d9c, 0xc1d82b6c6cad6c47, - 0xf562a43131c43195, 0xb9e8f37474cd7487, 0x09f115f6f6fff6e3, 0x438c4c464605460a, - 0x2645a5acac8aac09, 0x970fb589891e893c, 0x4428b414145014a0, 0x42dfbae1e1a3e15b, - 0x4e2ca616165816b0, 0xd274f73a3ae83acd, 0xd0d2066969b9696f, 0x2d12410909240948, - 0xade0d77070dd70a7, 0x54716fb6b6e2b6d9, 0xb7bd1ed0d067d0ce, 0x7ec7d6eded93ed3b, - 0xdb85e2cccc17cc2e, 0x578468424215422a, 0xc22d2c98985a98b4, 0x0e55eda4a4aaa449, - 0x8850752828a0285d, 0x31b8865c5c6d5cda, 0x3fed6bf8f8c7f893, 0xa411c28686228644, -} - -C4 := [256]u64 { - 0xc07830d818186018, 0x05af462623238c23, 0x7ef991b8c6c63fc6, 0x136fcdfbe8e887e8, - 0x4ca113cb87872687, 0xa9626d11b8b8dab8, 0x0805020901010401, 0x426e9e0d4f4f214f, - 0xadee6c9b3636d836, 0x590451ffa6a6a2a6, 0xdebdb90cd2d26fd2, 0xfb06f70ef5f5f3f5, - 0xef80f2967979f979, 0x5fcede306f6fa16f, 0xfcef3f6d91917e91, 0xaa07a4f852525552, - 0x27fdc04760609d60, 0x89766535bcbccabc, 0xaccd2b379b9b569b, 0x048c018a8e8e028e, - 0x71155bd2a3a3b6a3, 0x603c186c0c0c300c, 0xff8af6847b7bf17b, 0xb5e16a803535d435, - 0xe8693af51d1d741d, 0x5347ddb3e0e0a7e0, 0xf6acb321d7d77bd7, 0x5eed999cc2c22fc2, - 0x6d965c432e2eb82e, 0x627a96294b4b314b, 0xa321e15dfefedffe, 0x8216aed557574157, - 0xa8412abd15155415, 0x9fb6eee87777c177, 0xa5eb6e923737dc37, 0x7b56d79ee5e5b3e5, - 0x8cd923139f9f469f, 0xd317fd23f0f0e7f0, 0x6a7f94204a4a354a, 0x9e95a944dada4fda, - 0xfa25b0a258587d58, 0x06ca8fcfc9c903c9, 0x558d527c2929a429, 0x5022145a0a0a280a, - 0xe14f7f50b1b1feb1, 0x691a5dc9a0a0baa0, 0x7fdad6146b6bb16b, 0x5cab17d985852e85, - 0x8173673cbdbdcebd, 0xd234ba8f5d5d695d, 0x8050209010104010, 0xf303f507f4f4f7f4, - 0x16c08bddcbcb0bcb, 0xedc67cd33e3ef83e, 0x28110a2d05051405, 0x1fe6ce7867678167, - 0x7353d597e4e4b7e4, 0x25bb4e0227279c27, 0x3258827341411941, 0x2c9d0ba78b8b168b, - 0x510153f6a7a7a6a7, 0xcf94fab27d7de97d, 0xdcfb374995956e95, 0x8e9fad56d8d847d8, - 0x8b30eb70fbfbcbfb, 0x2371c1cdeeee9fee, 0xc791f8bb7c7ced7c, 0x17e3cc7166668566, - 0xa68ea77bdddd53dd, 0xb84b2eaf17175c17, 0x02468e4547470147, 0x84dc211a9e9e429e, - 0x1ec589d4caca0fca, 0x75995a582d2db42d, 0x9179632ebfbfc6bf, 0x381b0e3f07071c07, - 0x012347acadad8ead, 0xea2fb4b05a5a755a, 0x6cb51bef83833683, 0x85ff66b63333cc33, - 0x3ff2c65c63639163, 0x100a041202020802, 0x39384993aaaa92aa, 0xafa8e2de7171d971, - 0x0ecf8dc6c8c807c8, 0xc87d32d119196419, 0x7270923b49493949, 0x869aaf5fd9d943d9, - 0xc31df931f2f2eff2, 0x4b48dba8e3e3abe3, 0xe22ab6b95b5b715b, 0x34920dbc88881a88, - 0xa4c8293e9a9a529a, 0x2dbe4c0b26269826, 0x8dfa64bf3232c832, 0xe94a7d59b0b0fab0, - 0x1b6acff2e9e983e9, 0x78331e770f0f3c0f, 0xe6a6b733d5d573d5, 0x74ba1df480803a80, - 0x997c6127bebec2be, 0x26de87ebcdcd13cd, 0xbde468893434d034, 0x7a75903248483d48, - 0xab24e354ffffdbff, 0xf78ff48d7a7af57a, 0xf4ea3d6490907a90, 0xc23ebe9d5f5f615f, - 0x1da0403d20208020, 0x67d5d00f6868bd68, 0xd07234ca1a1a681a, 0x192c41b7aeae82ae, - 0xc95e757db4b4eab4, 0x9a19a8ce54544d54, 0xece53b7f93937693, 0x0daa442f22228822, - 0x07e9c86364648d64, 0xdb12ff2af1f1e3f1, 0xbfa2e6cc7373d173, 0x905a248212124812, - 0x3a5d807a40401d40, 0x4028104808082008, 0x56e89b95c3c32bc3, 0x337bc5dfecec97ec, - 0x9690ab4ddbdb4bdb, 0x611f5fc0a1a1bea1, 0x1c8307918d8d0e8d, 0xf5c97ac83d3df43d, - 0xccf1335b97976697, 0x0000000000000000, 0x36d483f9cfcf1bcf, 0x4587566e2b2bac2b, - 0x97b3ece17676c576, 0x64b019e682823282, 0xfea9b128d6d67fd6, 0xd87736c31b1b6c1b, - 0xc15b7774b5b5eeb5, 0x112943beafaf86af, 0x77dfd41d6a6ab56a, 0xba0da0ea50505d50, - 0x124c8a5745450945, 0xcb18fb38f3f3ebf3, 0x9df060ad3030c030, 0x2b74c3c4efef9bef, - 0xe5c37eda3f3ffc3f, 0x921caac755554955, 0x791059dba2a2b2a2, 0x0365c9e9eaea8fea, - 0x0fecca6a65658965, 0xb9686903babad2ba, 0x65935e4a2f2fbc2f, 0x4ee79d8ec0c027c0, - 0xbe81a160dede5fde, 0xe06c38fc1c1c701c, 0xbb2ee746fdfdd3fd, 0x52649a1f4d4d294d, - 0xe4e0397692927292, 0x8fbceafa7575c975, 0x301e0c3606061806, 0x249809ae8a8a128a, - 0xf940794bb2b2f2b2, 0x6359d185e6e6bfe6, 0x70361c7e0e0e380e, 0xf8633ee71f1f7c1f, - 0x37f7c45562629562, 0xeea3b53ad4d477d4, 0x29324d81a8a89aa8, 0xc4f4315296966296, - 0x9b3aef62f9f9c3f9, 0x66f697a3c5c533c5, 0x35b14a1025259425, 0xf220b2ab59597959, - 0x54ae15d084842a84, 0xb7a7e4c57272d572, 0xd5dd72ec3939e439, 0x5a6198164c4c2d4c, - 0xca3bbc945e5e655e, 0xe785f09f7878fd78, 0xddd870e53838e038, 0x148605988c8c0a8c, - 0xc6b2bf17d1d163d1, 0x410b57e4a5a5aea5, 0x434dd9a1e2e2afe2, 0x2ff8c24e61619961, - 0xf1457b42b3b3f6b3, 0x15a5423421218421, 0x94d625089c9c4a9c, 0xf0663cee1e1e781e, - 0x2252866143431143, 0x76fc93b1c7c73bc7, 0xb32be54ffcfcd7fc, 0x2014082404041004, - 0xb208a2e351515951, 0xbcc72f2599995e99, 0x4fc4da226d6da96d, 0x68391a650d0d340d, - 0x8335e979fafacffa, 0xb684a369dfdf5bdf, 0xd79bfca97e7ee57e, 0x3db4481924249024, - 0xc5d776fe3b3bec3b, 0x313d4b9aabab96ab, 0x3ed181f0cece1fce, 0x8855229911114411, - 0x0c8903838f8f068f, 0x4a6b9c044e4e254e, 0xd1517366b7b7e6b7, 0x0b60cbe0ebeb8beb, - 0xfdcc78c13c3cf03c, 0x7cbf1ffd81813e81, 0xd4fe354094946a94, 0xeb0cf31cf7f7fbf7, - 0xa1676f18b9b9deb9, 0x985f268b13134c13, 0x7d9c58512c2cb02c, 0xd6b8bb05d3d36bd3, - 0x6b5cd38ce7e7bbe7, 0x57cbdc396e6ea56e, 0x6ef395aac4c437c4, 0x180f061b03030c03, - 0x8a13acdc56564556, 0x1a49885e44440d44, 0xdf9efea07f7fe17f, 0x21374f88a9a99ea9, - 0x4d8254672a2aa82a, 0xb16d6b0abbbbd6bb, 0x46e29f87c1c123c1, 0xa202a6f153535153, - 0xae8ba572dcdc57dc, 0x582716530b0b2c0b, 0x9cd327019d9d4e9d, 0x47c1d82b6c6cad6c, - 0x95f562a43131c431, 0x87b9e8f37474cd74, 0xe309f115f6f6fff6, 0x0a438c4c46460546, - 0x092645a5acac8aac, 0x3c970fb589891e89, 0xa04428b414145014, 0x5b42dfbae1e1a3e1, - 0xb04e2ca616165816, 0xcdd274f73a3ae83a, 0x6fd0d2066969b969, 0x482d124109092409, - 0xa7ade0d77070dd70, 0xd954716fb6b6e2b6, 0xceb7bd1ed0d067d0, 0x3b7ec7d6eded93ed, - 0x2edb85e2cccc17cc, 0x2a57846842421542, 0xb4c22d2c98985a98, 0x490e55eda4a4aaa4, - 0x5d8850752828a028, 0xda31b8865c5c6d5c, 0x933fed6bf8f8c7f8, 0x44a411c286862286, -} - -C5 := [256]u64 { - 0x18c07830d8181860, 0x2305af462623238c, 0xc67ef991b8c6c63f, 0xe8136fcdfbe8e887, - 0x874ca113cb878726, 0xb8a9626d11b8b8da, 0x0108050209010104, 0x4f426e9e0d4f4f21, - 0x36adee6c9b3636d8, 0xa6590451ffa6a6a2, 0xd2debdb90cd2d26f, 0xf5fb06f70ef5f5f3, - 0x79ef80f2967979f9, 0x6f5fcede306f6fa1, 0x91fcef3f6d91917e, 0x52aa07a4f8525255, - 0x6027fdc04760609d, 0xbc89766535bcbcca, 0x9baccd2b379b9b56, 0x8e048c018a8e8e02, - 0xa371155bd2a3a3b6, 0x0c603c186c0c0c30, 0x7bff8af6847b7bf1, 0x35b5e16a803535d4, - 0x1de8693af51d1d74, 0xe05347ddb3e0e0a7, 0xd7f6acb321d7d77b, 0xc25eed999cc2c22f, - 0x2e6d965c432e2eb8, 0x4b627a96294b4b31, 0xfea321e15dfefedf, 0x578216aed5575741, - 0x15a8412abd151554, 0x779fb6eee87777c1, 0x37a5eb6e923737dc, 0xe57b56d79ee5e5b3, - 0x9f8cd923139f9f46, 0xf0d317fd23f0f0e7, 0x4a6a7f94204a4a35, 0xda9e95a944dada4f, - 0x58fa25b0a258587d, 0xc906ca8fcfc9c903, 0x29558d527c2929a4, 0x0a5022145a0a0a28, - 0xb1e14f7f50b1b1fe, 0xa0691a5dc9a0a0ba, 0x6b7fdad6146b6bb1, 0x855cab17d985852e, - 0xbd8173673cbdbdce, 0x5dd234ba8f5d5d69, 0x1080502090101040, 0xf4f303f507f4f4f7, - 0xcb16c08bddcbcb0b, 0x3eedc67cd33e3ef8, 0x0528110a2d050514, 0x671fe6ce78676781, - 0xe47353d597e4e4b7, 0x2725bb4e0227279c, 0x4132588273414119, 0x8b2c9d0ba78b8b16, - 0xa7510153f6a7a7a6, 0x7dcf94fab27d7de9, 0x95dcfb374995956e, 0xd88e9fad56d8d847, - 0xfb8b30eb70fbfbcb, 0xee2371c1cdeeee9f, 0x7cc791f8bb7c7ced, 0x6617e3cc71666685, - 0xdda68ea77bdddd53, 0x17b84b2eaf17175c, 0x4702468e45474701, 0x9e84dc211a9e9e42, - 0xca1ec589d4caca0f, 0x2d75995a582d2db4, 0xbf9179632ebfbfc6, 0x07381b0e3f07071c, - 0xad012347acadad8e, 0x5aea2fb4b05a5a75, 0x836cb51bef838336, 0x3385ff66b63333cc, - 0x633ff2c65c636391, 0x02100a0412020208, 0xaa39384993aaaa92, 0x71afa8e2de7171d9, - 0xc80ecf8dc6c8c807, 0x19c87d32d1191964, 0x497270923b494939, 0xd9869aaf5fd9d943, - 0xf2c31df931f2f2ef, 0xe34b48dba8e3e3ab, 0x5be22ab6b95b5b71, 0x8834920dbc88881a, - 0x9aa4c8293e9a9a52, 0x262dbe4c0b262698, 0x328dfa64bf3232c8, 0xb0e94a7d59b0b0fa, - 0xe91b6acff2e9e983, 0x0f78331e770f0f3c, 0xd5e6a6b733d5d573, 0x8074ba1df480803a, - 0xbe997c6127bebec2, 0xcd26de87ebcdcd13, 0x34bde468893434d0, 0x487a75903248483d, - 0xffab24e354ffffdb, 0x7af78ff48d7a7af5, 0x90f4ea3d6490907a, 0x5fc23ebe9d5f5f61, - 0x201da0403d202080, 0x6867d5d00f6868bd, 0x1ad07234ca1a1a68, 0xae192c41b7aeae82, - 0xb4c95e757db4b4ea, 0x549a19a8ce54544d, 0x93ece53b7f939376, 0x220daa442f222288, - 0x6407e9c86364648d, 0xf1db12ff2af1f1e3, 0x73bfa2e6cc7373d1, 0x12905a2482121248, - 0x403a5d807a40401d, 0x0840281048080820, 0xc356e89b95c3c32b, 0xec337bc5dfecec97, - 0xdb9690ab4ddbdb4b, 0xa1611f5fc0a1a1be, 0x8d1c8307918d8d0e, 0x3df5c97ac83d3df4, - 0x97ccf1335b979766, 0x0000000000000000, 0xcf36d483f9cfcf1b, 0x2b4587566e2b2bac, - 0x7697b3ece17676c5, 0x8264b019e6828232, 0xd6fea9b128d6d67f, 0x1bd87736c31b1b6c, - 0xb5c15b7774b5b5ee, 0xaf112943beafaf86, 0x6a77dfd41d6a6ab5, 0x50ba0da0ea50505d, - 0x45124c8a57454509, 0xf3cb18fb38f3f3eb, 0x309df060ad3030c0, 0xef2b74c3c4efef9b, - 0x3fe5c37eda3f3ffc, 0x55921caac7555549, 0xa2791059dba2a2b2, 0xea0365c9e9eaea8f, - 0x650fecca6a656589, 0xbab9686903babad2, 0x2f65935e4a2f2fbc, 0xc04ee79d8ec0c027, - 0xdebe81a160dede5f, 0x1ce06c38fc1c1c70, 0xfdbb2ee746fdfdd3, 0x4d52649a1f4d4d29, - 0x92e4e03976929272, 0x758fbceafa7575c9, 0x06301e0c36060618, 0x8a249809ae8a8a12, - 0xb2f940794bb2b2f2, 0xe66359d185e6e6bf, 0x0e70361c7e0e0e38, 0x1ff8633ee71f1f7c, - 0x6237f7c455626295, 0xd4eea3b53ad4d477, 0xa829324d81a8a89a, 0x96c4f43152969662, - 0xf99b3aef62f9f9c3, 0xc566f697a3c5c533, 0x2535b14a10252594, 0x59f220b2ab595979, - 0x8454ae15d084842a, 0x72b7a7e4c57272d5, 0x39d5dd72ec3939e4, 0x4c5a6198164c4c2d, - 0x5eca3bbc945e5e65, 0x78e785f09f7878fd, 0x38ddd870e53838e0, 0x8c148605988c8c0a, - 0xd1c6b2bf17d1d163, 0xa5410b57e4a5a5ae, 0xe2434dd9a1e2e2af, 0x612ff8c24e616199, - 0xb3f1457b42b3b3f6, 0x2115a54234212184, 0x9c94d625089c9c4a, 0x1ef0663cee1e1e78, - 0x4322528661434311, 0xc776fc93b1c7c73b, 0xfcb32be54ffcfcd7, 0x0420140824040410, - 0x51b208a2e3515159, 0x99bcc72f2599995e, 0x6d4fc4da226d6da9, 0x0d68391a650d0d34, - 0xfa8335e979fafacf, 0xdfb684a369dfdf5b, 0x7ed79bfca97e7ee5, 0x243db44819242490, - 0x3bc5d776fe3b3bec, 0xab313d4b9aabab96, 0xce3ed181f0cece1f, 0x1188552299111144, - 0x8f0c8903838f8f06, 0x4e4a6b9c044e4e25, 0xb7d1517366b7b7e6, 0xeb0b60cbe0ebeb8b, - 0x3cfdcc78c13c3cf0, 0x817cbf1ffd81813e, 0x94d4fe354094946a, 0xf7eb0cf31cf7f7fb, - 0xb9a1676f18b9b9de, 0x13985f268b13134c, 0x2c7d9c58512c2cb0, 0xd3d6b8bb05d3d36b, - 0xe76b5cd38ce7e7bb, 0x6e57cbdc396e6ea5, 0xc46ef395aac4c437, 0x03180f061b03030c, - 0x568a13acdc565645, 0x441a49885e44440d, 0x7fdf9efea07f7fe1, 0xa921374f88a9a99e, - 0x2a4d8254672a2aa8, 0xbbb16d6b0abbbbd6, 0xc146e29f87c1c123, 0x53a202a6f1535351, - 0xdcae8ba572dcdc57, 0x0b582716530b0b2c, 0x9d9cd327019d9d4e, 0x6c47c1d82b6c6cad, - 0x3195f562a43131c4, 0x7487b9e8f37474cd, 0xf6e309f115f6f6ff, 0x460a438c4c464605, - 0xac092645a5acac8a, 0x893c970fb589891e, 0x14a04428b4141450, 0xe15b42dfbae1e1a3, - 0x16b04e2ca6161658, 0x3acdd274f73a3ae8, 0x696fd0d2066969b9, 0x09482d1241090924, - 0x70a7ade0d77070dd, 0xb6d954716fb6b6e2, 0xd0ceb7bd1ed0d067, 0xed3b7ec7d6eded93, - 0xcc2edb85e2cccc17, 0x422a578468424215, 0x98b4c22d2c98985a, 0xa4490e55eda4a4aa, - 0x285d8850752828a0, 0x5cda31b8865c5c6d, 0xf8933fed6bf8f8c7, 0x8644a411c2868622, -} - -C6 := [256]u64 { - 0x6018c07830d81818, 0x8c2305af46262323, 0x3fc67ef991b8c6c6, 0x87e8136fcdfbe8e8, - 0x26874ca113cb8787, 0xdab8a9626d11b8b8, 0x0401080502090101, 0x214f426e9e0d4f4f, - 0xd836adee6c9b3636, 0xa2a6590451ffa6a6, 0x6fd2debdb90cd2d2, 0xf3f5fb06f70ef5f5, - 0xf979ef80f2967979, 0xa16f5fcede306f6f, 0x7e91fcef3f6d9191, 0x5552aa07a4f85252, - 0x9d6027fdc0476060, 0xcabc89766535bcbc, 0x569baccd2b379b9b, 0x028e048c018a8e8e, - 0xb6a371155bd2a3a3, 0x300c603c186c0c0c, 0xf17bff8af6847b7b, 0xd435b5e16a803535, - 0x741de8693af51d1d, 0xa7e05347ddb3e0e0, 0x7bd7f6acb321d7d7, 0x2fc25eed999cc2c2, - 0xb82e6d965c432e2e, 0x314b627a96294b4b, 0xdffea321e15dfefe, 0x41578216aed55757, - 0x5415a8412abd1515, 0xc1779fb6eee87777, 0xdc37a5eb6e923737, 0xb3e57b56d79ee5e5, - 0x469f8cd923139f9f, 0xe7f0d317fd23f0f0, 0x354a6a7f94204a4a, 0x4fda9e95a944dada, - 0x7d58fa25b0a25858, 0x03c906ca8fcfc9c9, 0xa429558d527c2929, 0x280a5022145a0a0a, - 0xfeb1e14f7f50b1b1, 0xbaa0691a5dc9a0a0, 0xb16b7fdad6146b6b, 0x2e855cab17d98585, - 0xcebd8173673cbdbd, 0x695dd234ba8f5d5d, 0x4010805020901010, 0xf7f4f303f507f4f4, - 0x0bcb16c08bddcbcb, 0xf83eedc67cd33e3e, 0x140528110a2d0505, 0x81671fe6ce786767, - 0xb7e47353d597e4e4, 0x9c2725bb4e022727, 0x1941325882734141, 0x168b2c9d0ba78b8b, - 0xa6a7510153f6a7a7, 0xe97dcf94fab27d7d, 0x6e95dcfb37499595, 0x47d88e9fad56d8d8, - 0xcbfb8b30eb70fbfb, 0x9fee2371c1cdeeee, 0xed7cc791f8bb7c7c, 0x856617e3cc716666, - 0x53dda68ea77bdddd, 0x5c17b84b2eaf1717, 0x014702468e454747, 0x429e84dc211a9e9e, - 0x0fca1ec589d4caca, 0xb42d75995a582d2d, 0xc6bf9179632ebfbf, 0x1c07381b0e3f0707, - 0x8ead012347acadad, 0x755aea2fb4b05a5a, 0x36836cb51bef8383, 0xcc3385ff66b63333, - 0x91633ff2c65c6363, 0x0802100a04120202, 0x92aa39384993aaaa, 0xd971afa8e2de7171, - 0x07c80ecf8dc6c8c8, 0x6419c87d32d11919, 0x39497270923b4949, 0x43d9869aaf5fd9d9, - 0xeff2c31df931f2f2, 0xabe34b48dba8e3e3, 0x715be22ab6b95b5b, 0x1a8834920dbc8888, - 0x529aa4c8293e9a9a, 0x98262dbe4c0b2626, 0xc8328dfa64bf3232, 0xfab0e94a7d59b0b0, - 0x83e91b6acff2e9e9, 0x3c0f78331e770f0f, 0x73d5e6a6b733d5d5, 0x3a8074ba1df48080, - 0xc2be997c6127bebe, 0x13cd26de87ebcdcd, 0xd034bde468893434, 0x3d487a7590324848, - 0xdbffab24e354ffff, 0xf57af78ff48d7a7a, 0x7a90f4ea3d649090, 0x615fc23ebe9d5f5f, - 0x80201da0403d2020, 0xbd6867d5d00f6868, 0x681ad07234ca1a1a, 0x82ae192c41b7aeae, - 0xeab4c95e757db4b4, 0x4d549a19a8ce5454, 0x7693ece53b7f9393, 0x88220daa442f2222, - 0x8d6407e9c8636464, 0xe3f1db12ff2af1f1, 0xd173bfa2e6cc7373, 0x4812905a24821212, - 0x1d403a5d807a4040, 0x2008402810480808, 0x2bc356e89b95c3c3, 0x97ec337bc5dfecec, - 0x4bdb9690ab4ddbdb, 0xbea1611f5fc0a1a1, 0x0e8d1c8307918d8d, 0xf43df5c97ac83d3d, - 0x6697ccf1335b9797, 0x0000000000000000, 0x1bcf36d483f9cfcf, 0xac2b4587566e2b2b, - 0xc57697b3ece17676, 0x328264b019e68282, 0x7fd6fea9b128d6d6, 0x6c1bd87736c31b1b, - 0xeeb5c15b7774b5b5, 0x86af112943beafaf, 0xb56a77dfd41d6a6a, 0x5d50ba0da0ea5050, - 0x0945124c8a574545, 0xebf3cb18fb38f3f3, 0xc0309df060ad3030, 0x9bef2b74c3c4efef, - 0xfc3fe5c37eda3f3f, 0x4955921caac75555, 0xb2a2791059dba2a2, 0x8fea0365c9e9eaea, - 0x89650fecca6a6565, 0xd2bab9686903baba, 0xbc2f65935e4a2f2f, 0x27c04ee79d8ec0c0, - 0x5fdebe81a160dede, 0x701ce06c38fc1c1c, 0xd3fdbb2ee746fdfd, 0x294d52649a1f4d4d, - 0x7292e4e039769292, 0xc9758fbceafa7575, 0x1806301e0c360606, 0x128a249809ae8a8a, - 0xf2b2f940794bb2b2, 0xbfe66359d185e6e6, 0x380e70361c7e0e0e, 0x7c1ff8633ee71f1f, - 0x956237f7c4556262, 0x77d4eea3b53ad4d4, 0x9aa829324d81a8a8, 0x6296c4f431529696, - 0xc3f99b3aef62f9f9, 0x33c566f697a3c5c5, 0x942535b14a102525, 0x7959f220b2ab5959, - 0x2a8454ae15d08484, 0xd572b7a7e4c57272, 0xe439d5dd72ec3939, 0x2d4c5a6198164c4c, - 0x655eca3bbc945e5e, 0xfd78e785f09f7878, 0xe038ddd870e53838, 0x0a8c148605988c8c, - 0x63d1c6b2bf17d1d1, 0xaea5410b57e4a5a5, 0xafe2434dd9a1e2e2, 0x99612ff8c24e6161, - 0xf6b3f1457b42b3b3, 0x842115a542342121, 0x4a9c94d625089c9c, 0x781ef0663cee1e1e, - 0x1143225286614343, 0x3bc776fc93b1c7c7, 0xd7fcb32be54ffcfc, 0x1004201408240404, - 0x5951b208a2e35151, 0x5e99bcc72f259999, 0xa96d4fc4da226d6d, 0x340d68391a650d0d, - 0xcffa8335e979fafa, 0x5bdfb684a369dfdf, 0xe57ed79bfca97e7e, 0x90243db448192424, - 0xec3bc5d776fe3b3b, 0x96ab313d4b9aabab, 0x1fce3ed181f0cece, 0x4411885522991111, - 0x068f0c8903838f8f, 0x254e4a6b9c044e4e, 0xe6b7d1517366b7b7, 0x8beb0b60cbe0ebeb, - 0xf03cfdcc78c13c3c, 0x3e817cbf1ffd8181, 0x6a94d4fe35409494, 0xfbf7eb0cf31cf7f7, - 0xdeb9a1676f18b9b9, 0x4c13985f268b1313, 0xb02c7d9c58512c2c, 0x6bd3d6b8bb05d3d3, - 0xbbe76b5cd38ce7e7, 0xa56e57cbdc396e6e, 0x37c46ef395aac4c4, 0x0c03180f061b0303, - 0x45568a13acdc5656, 0x0d441a49885e4444, 0xe17fdf9efea07f7f, 0x9ea921374f88a9a9, - 0xa82a4d8254672a2a, 0xd6bbb16d6b0abbbb, 0x23c146e29f87c1c1, 0x5153a202a6f15353, - 0x57dcae8ba572dcdc, 0x2c0b582716530b0b, 0x4e9d9cd327019d9d, 0xad6c47c1d82b6c6c, - 0xc43195f562a43131, 0xcd7487b9e8f37474, 0xfff6e309f115f6f6, 0x05460a438c4c4646, - 0x8aac092645a5acac, 0x1e893c970fb58989, 0x5014a04428b41414, 0xa3e15b42dfbae1e1, - 0x5816b04e2ca61616, 0xe83acdd274f73a3a, 0xb9696fd0d2066969, 0x2409482d12410909, - 0xdd70a7ade0d77070, 0xe2b6d954716fb6b6, 0x67d0ceb7bd1ed0d0, 0x93ed3b7ec7d6eded, - 0x17cc2edb85e2cccc, 0x15422a5784684242, 0x5a98b4c22d2c9898, 0xaaa4490e55eda4a4, - 0xa0285d8850752828, 0x6d5cda31b8865c5c, 0xc7f8933fed6bf8f8, 0x228644a411c28686, -} - -C7 := [256]u64 { - 0x186018c07830d818, 0x238c2305af462623, 0xc63fc67ef991b8c6, 0xe887e8136fcdfbe8, - 0x8726874ca113cb87, 0xb8dab8a9626d11b8, 0x0104010805020901, 0x4f214f426e9e0d4f, - 0x36d836adee6c9b36, 0xa6a2a6590451ffa6, 0xd26fd2debdb90cd2, 0xf5f3f5fb06f70ef5, - 0x79f979ef80f29679, 0x6fa16f5fcede306f, 0x917e91fcef3f6d91, 0x525552aa07a4f852, - 0x609d6027fdc04760, 0xbccabc89766535bc, 0x9b569baccd2b379b, 0x8e028e048c018a8e, - 0xa3b6a371155bd2a3, 0x0c300c603c186c0c, 0x7bf17bff8af6847b, 0x35d435b5e16a8035, - 0x1d741de8693af51d, 0xe0a7e05347ddb3e0, 0xd77bd7f6acb321d7, 0xc22fc25eed999cc2, - 0x2eb82e6d965c432e, 0x4b314b627a96294b, 0xfedffea321e15dfe, 0x5741578216aed557, - 0x155415a8412abd15, 0x77c1779fb6eee877, 0x37dc37a5eb6e9237, 0xe5b3e57b56d79ee5, - 0x9f469f8cd923139f, 0xf0e7f0d317fd23f0, 0x4a354a6a7f94204a, 0xda4fda9e95a944da, - 0x587d58fa25b0a258, 0xc903c906ca8fcfc9, 0x29a429558d527c29, 0x0a280a5022145a0a, - 0xb1feb1e14f7f50b1, 0xa0baa0691a5dc9a0, 0x6bb16b7fdad6146b, 0x852e855cab17d985, - 0xbdcebd8173673cbd, 0x5d695dd234ba8f5d, 0x1040108050209010, 0xf4f7f4f303f507f4, - 0xcb0bcb16c08bddcb, 0x3ef83eedc67cd33e, 0x05140528110a2d05, 0x6781671fe6ce7867, - 0xe4b7e47353d597e4, 0x279c2725bb4e0227, 0x4119413258827341, 0x8b168b2c9d0ba78b, - 0xa7a6a7510153f6a7, 0x7de97dcf94fab27d, 0x956e95dcfb374995, 0xd847d88e9fad56d8, - 0xfbcbfb8b30eb70fb, 0xee9fee2371c1cdee, 0x7ced7cc791f8bb7c, 0x66856617e3cc7166, - 0xdd53dda68ea77bdd, 0x175c17b84b2eaf17, 0x47014702468e4547, 0x9e429e84dc211a9e, - 0xca0fca1ec589d4ca, 0x2db42d75995a582d, 0xbfc6bf9179632ebf, 0x071c07381b0e3f07, - 0xad8ead012347acad, 0x5a755aea2fb4b05a, 0x8336836cb51bef83, 0x33cc3385ff66b633, - 0x6391633ff2c65c63, 0x020802100a041202, 0xaa92aa39384993aa, 0x71d971afa8e2de71, - 0xc807c80ecf8dc6c8, 0x196419c87d32d119, 0x4939497270923b49, 0xd943d9869aaf5fd9, - 0xf2eff2c31df931f2, 0xe3abe34b48dba8e3, 0x5b715be22ab6b95b, 0x881a8834920dbc88, - 0x9a529aa4c8293e9a, 0x2698262dbe4c0b26, 0x32c8328dfa64bf32, 0xb0fab0e94a7d59b0, - 0xe983e91b6acff2e9, 0x0f3c0f78331e770f, 0xd573d5e6a6b733d5, 0x803a8074ba1df480, - 0xbec2be997c6127be, 0xcd13cd26de87ebcd, 0x34d034bde4688934, 0x483d487a75903248, - 0xffdbffab24e354ff, 0x7af57af78ff48d7a, 0x907a90f4ea3d6490, 0x5f615fc23ebe9d5f, - 0x2080201da0403d20, 0x68bd6867d5d00f68, 0x1a681ad07234ca1a, 0xae82ae192c41b7ae, - 0xb4eab4c95e757db4, 0x544d549a19a8ce54, 0x937693ece53b7f93, 0x2288220daa442f22, - 0x648d6407e9c86364, 0xf1e3f1db12ff2af1, 0x73d173bfa2e6cc73, 0x124812905a248212, - 0x401d403a5d807a40, 0x0820084028104808, 0xc32bc356e89b95c3, 0xec97ec337bc5dfec, - 0xdb4bdb9690ab4ddb, 0xa1bea1611f5fc0a1, 0x8d0e8d1c8307918d, 0x3df43df5c97ac83d, - 0x976697ccf1335b97, 0x0000000000000000, 0xcf1bcf36d483f9cf, 0x2bac2b4587566e2b, - 0x76c57697b3ece176, 0x82328264b019e682, 0xd67fd6fea9b128d6, 0x1b6c1bd87736c31b, - 0xb5eeb5c15b7774b5, 0xaf86af112943beaf, 0x6ab56a77dfd41d6a, 0x505d50ba0da0ea50, - 0x450945124c8a5745, 0xf3ebf3cb18fb38f3, 0x30c0309df060ad30, 0xef9bef2b74c3c4ef, - 0x3ffc3fe5c37eda3f, 0x554955921caac755, 0xa2b2a2791059dba2, 0xea8fea0365c9e9ea, - 0x6589650fecca6a65, 0xbad2bab9686903ba, 0x2fbc2f65935e4a2f, 0xc027c04ee79d8ec0, - 0xde5fdebe81a160de, 0x1c701ce06c38fc1c, 0xfdd3fdbb2ee746fd, 0x4d294d52649a1f4d, - 0x927292e4e0397692, 0x75c9758fbceafa75, 0x061806301e0c3606, 0x8a128a249809ae8a, - 0xb2f2b2f940794bb2, 0xe6bfe66359d185e6, 0x0e380e70361c7e0e, 0x1f7c1ff8633ee71f, - 0x62956237f7c45562, 0xd477d4eea3b53ad4, 0xa89aa829324d81a8, 0x966296c4f4315296, - 0xf9c3f99b3aef62f9, 0xc533c566f697a3c5, 0x25942535b14a1025, 0x597959f220b2ab59, - 0x842a8454ae15d084, 0x72d572b7a7e4c572, 0x39e439d5dd72ec39, 0x4c2d4c5a6198164c, - 0x5e655eca3bbc945e, 0x78fd78e785f09f78, 0x38e038ddd870e538, 0x8c0a8c148605988c, - 0xd163d1c6b2bf17d1, 0xa5aea5410b57e4a5, 0xe2afe2434dd9a1e2, 0x6199612ff8c24e61, - 0xb3f6b3f1457b42b3, 0x21842115a5423421, 0x9c4a9c94d625089c, 0x1e781ef0663cee1e, - 0x4311432252866143, 0xc73bc776fc93b1c7, 0xfcd7fcb32be54ffc, 0x0410042014082404, - 0x515951b208a2e351, 0x995e99bcc72f2599, 0x6da96d4fc4da226d, 0x0d340d68391a650d, - 0xfacffa8335e979fa, 0xdf5bdfb684a369df, 0x7ee57ed79bfca97e, 0x2490243db4481924, - 0x3bec3bc5d776fe3b, 0xab96ab313d4b9aab, 0xce1fce3ed181f0ce, 0x1144118855229911, - 0x8f068f0c8903838f, 0x4e254e4a6b9c044e, 0xb7e6b7d1517366b7, 0xeb8beb0b60cbe0eb, - 0x3cf03cfdcc78c13c, 0x813e817cbf1ffd81, 0x946a94d4fe354094, 0xf7fbf7eb0cf31cf7, - 0xb9deb9a1676f18b9, 0x134c13985f268b13, 0x2cb02c7d9c58512c, 0xd36bd3d6b8bb05d3, - 0xe7bbe76b5cd38ce7, 0x6ea56e57cbdc396e, 0xc437c46ef395aac4, 0x030c03180f061b03, - 0x5645568a13acdc56, 0x440d441a49885e44, 0x7fe17fdf9efea07f, 0xa99ea921374f88a9, - 0x2aa82a4d8254672a, 0xbbd6bbb16d6b0abb, 0xc123c146e29f87c1, 0x535153a202a6f153, - 0xdc57dcae8ba572dc, 0x0b2c0b582716530b, 0x9d4e9d9cd327019d, 0x6cad6c47c1d82b6c, - 0x31c43195f562a431, 0x74cd7487b9e8f374, 0xf6fff6e309f115f6, 0x4605460a438c4c46, - 0xac8aac092645a5ac, 0x891e893c970fb589, 0x145014a04428b414, 0xe1a3e15b42dfbae1, - 0x165816b04e2ca616, 0x3ae83acdd274f73a, 0x69b9696fd0d20669, 0x092409482d124109, - 0x70dd70a7ade0d770, 0xb6e2b6d954716fb6, 0xd067d0ceb7bd1ed0, 0xed93ed3b7ec7d6ed, - 0xcc17cc2edb85e2cc, 0x4215422a57846842, 0x985a98b4c22d2c98, 0xa4aaa4490e55eda4, - 0x28a0285d88507528, 0x5c6d5cda31b8865c, 0xf8c7f8933fed6bf8, 0x86228644a411c286, -} - -RC := [ROUNDS + 1]u64 { - 0x0000000000000000, - 0x1823c6e887b8014f, - 0x36a6d2f5796f9152, - 0x60bc9b8ea30c7b35, - 0x1de0d7c22e4bfe57, - 0x157737e59ff04ada, - 0x58c9290ab1a06b85, - 0xbd5d10f4cb3e0567, - 0xe427418ba77d95d8, - 0xfbee7c66dd17479e, - 0xca2dbf07ad5a8333, -} - -transform :: proc (ctx: ^Whirlpool_Context) { - K, block, state, L: [8]u64 - - for i := 0; i < 8; i += 1 {block[i] = util.U64_BE(ctx.buffer[8 * i:])} - - for i := 0; i < 8; i += 1 { - K[i] = ctx.hash[i] - state[i] = block[i] ~ K[i] - } - - for r := 1; r <= ROUNDS; r += 1 { - for i := 0; i < 8; i += 1 { - L[i] = C0[byte(K[i % 8] >> 56)] ~ - C1[byte(K[(i + 7) % 8] >> 48)] ~ - C2[byte(K[(i + 6) % 8] >> 40)] ~ - C3[byte(K[(i + 5) % 8] >> 32)] ~ - C4[byte(K[(i + 4) % 8] >> 24)] ~ - C5[byte(K[(i + 3) % 8] >> 16)] ~ - C6[byte(K[(i + 2) % 8] >> 8)] ~ - C7[byte(K[(i + 1) % 8])] - } - L[0] ~= RC[r] - - for i := 0; i < 8; i += 1 {K[i] = L[i]} - - for i := 0; i < 8; i += 1 { - L[i] = C0[byte(state[i % 8] >> 56)] ~ - C1[byte(state[(i + 7) % 8] >> 48)] ~ - C2[byte(state[(i + 6) % 8] >> 40)] ~ - C3[byte(state[(i + 5) % 8] >> 32)] ~ - C4[byte(state[(i + 4) % 8] >> 24)] ~ - C5[byte(state[(i + 3) % 8] >> 16)] ~ - C6[byte(state[(i + 2) % 8] >> 8)] ~ - C7[byte(state[(i + 1) % 8])] ~ - K[i % 8] - } - for i := 0; i < 8; i += 1 {state[i] = L[i]} - } - for i := 0; i < 8; i += 1 {ctx.hash[i] ~= state[i] ~ block[i]} -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 8c817dd82..33069cf71 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -36,7 +36,6 @@ import sha3 "core:crypto/sha3" import shake "core:crypto/shake" import sm3 "core:crypto/sm3" import crypto_util "core:crypto/util" -import whirlpool "core:crypto/whirlpool" import x25519 "core:crypto/x25519" import pe "core:debug/pe" @@ -152,7 +151,6 @@ _ :: sha3 _ :: shake _ :: sm3 _ :: crypto_util -_ :: whirlpool _ :: x25519 _ :: pe _ :: dynlib diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 1ae8b22d3..075276c11 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -10,7 +10,6 @@ import sha3 "vendor:botan/sha3" import shake "vendor:botan/shake" import siphash "vendor:botan/siphash" import sm3 "vendor:botan/sm3" -import whirlpool "vendor:botan/whirlpool" import cgltf "vendor:cgltf" // import commonmark "vendor:commonmark" @@ -50,7 +49,6 @@ _ :: sha3 _ :: shake _ :: siphash _ :: sm3 -_ :: whirlpool _ :: cgltf diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 60410c269..508af63ad 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -22,7 +22,6 @@ import "core:crypto/sha2" import "core:crypto/sha3" import "core:crypto/keccak" import "core:crypto/shake" -import "core:crypto/whirlpool" import "core:crypto/blake2b" import "core:crypto/blake2s" import "core:crypto/sm3" @@ -69,7 +68,6 @@ main :: proc() { test_keccak_256(&t) test_keccak_384(&t) test_keccak_512(&t) - test_whirlpool(&t) test_blake2b(&t) test_blake2s(&t) test_sm3(&t) @@ -416,32 +414,6 @@ test_keccak_512 :: proc(t: ^testing.T) { } } -@(test) -test_whirlpool :: proc(t: ^testing.T) { - // Test vectors from - // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html - test_vectors := [?]TestHash { - TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, - TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, - TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, - TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, - TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, - TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, - TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, - TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, - TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, - TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, - TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, - TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, - TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, - } - for v, _ in test_vectors { - computed := whirlpool.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_blake2b :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 897987721..661f79790 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -23,7 +23,6 @@ import "vendor:botan/sha2" import "vendor:botan/sha3" import "vendor:botan/keccak" import "vendor:botan/shake" -import "vendor:botan/whirlpool" import "vendor:botan/blake2b" import "vendor:botan/sm3" import "vendor:botan/siphash" @@ -66,7 +65,6 @@ main :: proc() { // test_shake_128(&t) // test_shake_256(&t) test_keccak_512(&t) - test_whirlpool(&t) test_blake2b(&t) test_sm3(&t) test_siphash_2_4(&t) @@ -340,32 +338,6 @@ test_keccak_512 :: proc(t: ^testing.T) { } } -@(test) -test_whirlpool :: proc(t: ^testing.T) { - // Test vectors from - // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html - test_vectors := [?]TestHash { - TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, - TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, - TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, - TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, - TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, - TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, - TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, - TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, - TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, - TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, - TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, - TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, - TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, - } - for v, _ in test_vectors { - computed := whirlpool.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - @(test) test_blake2b :: proc(t: ^testing.T) { test_vectors := [?]TestHash { diff --git a/vendor/botan/README.md b/vendor/botan/README.md index 560f207fd..890949158 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -16,7 +16,6 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | -| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | #### High level API Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`. diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin index 6b1f6ae41..f12d2493b 100644 --- a/vendor/botan/bindings/botan.odin +++ b/vendor/botan/bindings/botan.odin @@ -74,7 +74,6 @@ HASH_SHA3_512 :: "SHA-3(512)" HASH_SHAKE_128 :: "SHAKE-128" HASH_SHAKE_256 :: "SHAKE-256" HASH_KECCAK_512 :: "Keccak-1600" -HASH_WHIRLPOOL :: "Whirlpool" HASH_BLAKE2B :: "BLAKE2b" HASH_MD5 :: "MD5" HASH_SM3 :: "SM3" diff --git a/vendor/botan/whirlpool/whirlpool.odin b/vendor/botan/whirlpool/whirlpool.odin deleted file mode 100644 index 76d4d25d4..000000000 --- a/vendor/botan/whirlpool/whirlpool.odin +++ /dev/null @@ -1,121 +0,0 @@ -package vendor_whirlpool - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial implementation. - - Interface for the WHIRLPOOL hashing algorithm. - The hash will be computed via bindings to the Botan crypto library -*/ - -import "core:os" -import "core:io" - -import botan "../bindings" - -/* - High level API -*/ - -DIGEST_SIZE :: 64 - -// hash_string will hash the given input and return the -// computed hash -hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { - return hash_bytes(transmute([]byte)(data)) -} - -// hash_bytes will hash the given input and return the -// computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { - hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_WHIRLPOOL, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash -} - -// hash_string_to_buffer will hash the given input and assign the -// computed hash to the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_string_to_buffer :: proc(data: string, hash: []byte) { - hash_bytes_to_buffer(transmute([]byte)(data), hash) -} - -// hash_bytes_to_buffer will hash the given input and write the -// computed hash into the second parameter. -// It requires that the destination buffer is at least as big as the digest size -hash_bytes_to_buffer :: proc(data, hash: []byte) { - assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_WHIRLPOOL, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) -} - -// hash_stream will read the stream in chunks and compute a -// hash from its contents -hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { - hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_WHIRLPOOL, 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = io.read(s, buf) - if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true -} - -// hash_file will read the file provided by the given handle -// and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { - if !load_at_once { - return hash_stream(os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes(buf[:]), ok - } - } - return [DIGEST_SIZE]byte{}, false -} - -hash :: proc { - hash_stream, - hash_file, - hash_bytes, - hash_string, - hash_bytes_to_buffer, - hash_string_to_buffer, -} - -/* - Low level API -*/ - -Whirlpool_Context :: botan.hash_t - -init :: proc "contextless" (ctx: ^botan.hash_t) { - botan.hash_init(ctx, botan.HASH_WHIRLPOOL, 0) -} - -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { - botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) -} - -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { - botan.hash_final(ctx^, &hash[0]) - botan.hash_destroy(ctx^) -} From bc139ba6c6b00b4ce5e2947159f3e5ee7c57f19f Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 16 Nov 2023 22:07:14 +0900 Subject: [PATCH 101/160] core/crypto/util: Remove, no longer needed --- core/crypto/util/util.odin | 146 ------------------------------------- examples/all/all_main.odin | 2 - 2 files changed, 148 deletions(-) delete mode 100644 core/crypto/util/util.odin diff --git a/core/crypto/util/util.odin b/core/crypto/util/util.odin deleted file mode 100644 index b9b80124a..000000000 --- a/core/crypto/util/util.odin +++ /dev/null @@ -1,146 +0,0 @@ -package util - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - - Various utility procedures -*/ - -import "core:mem" -// Keep vet happy -_ :: mem - -// @note(bp): this can replace the other two -cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D { - src := src - dst := (^mem.Raw_Slice)(&src) - - when size_of(DE) < size_of(SE) { - when size_of(DE) % size_of(SE) == 0 { - dst.len /= size_of(SE) / size_of(DE) - } else { - dst.len *= size_of(SE) - dst.len /= size_of(DE) - } - } else when size_of(DE) > size_of(SE) { - when size_of(DE) % size_of(SE) == 0 { - dst.len *= size_of(DE) / size_of(SE) - } else { - dst.len *= size_of(SE) - dst.len /= size_of(DE) - } - } else when size_of(DE) != size_of(SE) { - #assert(size_of(DE) % size_of(SE) == 0, "Different size detected") - dst.len *= size_of(SE) - dst.len /= size_of(DE) - } - - return (^D)(dst)^ -} - -bytes_to_slice :: #force_inline proc "contextless" ($T: typeid/[]$E, bytes: []byte) -> T { - s := transmute(mem.Raw_Slice)bytes - s.len /= size_of(E) - return transmute(T)s -} - -slice_to_bytes :: #force_inline proc "contextless" (slice: $E/[]$T) -> []byte { - s := transmute(mem.Raw_Slice)slice - s.len *= size_of(T) - return transmute([]byte)s -} - -ROTL16 :: #force_inline proc "contextless" (a, b: u16) -> u16 { - return ((a << b) | (a >> (16 - b))) -} - -ROTR16 :: #force_inline proc "contextless" (a, b: u16) -> u16 { - return ((a >> b) | (a << (16 - b))) -} - -ROTL32 :: #force_inline proc "contextless"(a: u32, b: int) -> u32 { - s := uint(b) & 31 - return (a << s) | (a >> (32 - s)) -} - -ROTR32 :: #force_inline proc "contextless" (a: u32, b: int) -> u32 { - s := uint(b) & 31 - return (a >> s) | (a << (32 - s)) -} - -ROTL64 :: #force_inline proc "contextless" (a, b: u64) -> u64 { - return ((a << b) | (a >> (64 - b))) -} - -ROTR64 :: #force_inline proc "contextless" (a, b: u64) -> u64 { - return ((a >> b) | (a << (64 - b))) -} - -ROTL128 :: #force_inline proc "contextless" (a, b, c, d: ^u32, n: uint) { - a, b, c, d := a, b, c, d - t := a^ >> (32 - n) - a^ = ((a^ << n) | (b^ >> (32 - n))) - b^ = ((b^ << n) | (c^ >> (32 - n))) - c^ = ((c^ << n) | (d^ >> (32 - n))) - d^ = ((d^ << n) | t) -} - -U32_LE :: #force_inline proc "contextless" (b: []byte) -> u32 { - return u32(b[0]) | u32(b[1]) << 8 | u32(b[2]) << 16 | u32(b[3]) << 24 -} - -U64_LE :: #force_inline proc "contextless" (b: []byte) -> u64 { - return u64(b[0]) | u64(b[1]) << 8 | u64(b[2]) << 16 | u64(b[3]) << 24 | - u64(b[4]) << 32 | u64(b[5]) << 40 | u64(b[6]) << 48 | u64(b[7]) << 56 -} - -U64_BE :: #force_inline proc "contextless" (b: []byte) -> u64 { - return u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | - u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 -} - -PUT_U64_LE :: #force_inline proc "contextless" (b: []byte, v: u64) { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - b[4] = byte(v >> 32) - b[5] = byte(v >> 40) - b[6] = byte(v >> 48) - b[7] = byte(v >> 56) -} - -PUT_U32_LE :: #force_inline proc "contextless" (b: []byte, v: u32) { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) -} - -PUT_U32_BE :: #force_inline proc "contextless" (b: []byte, v: u32) { - b[0] = byte(v >> 24) - b[1] = byte(v >> 16) - b[2] = byte(v >> 8) - b[3] = byte(v) -} - -PUT_U64_BE :: #force_inline proc "contextless" (b: []byte, v: u64) { - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) -} - -XOR_BUF :: #force_inline proc "contextless" (input, output: []byte) { - for i := 0; i < len(input); i += 1 { - output[i] ~= input[i] - } -} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 33069cf71..bdbaf0e6c 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -35,7 +35,6 @@ import sha2 "core:crypto/sha2" import sha3 "core:crypto/sha3" import shake "core:crypto/shake" import sm3 "core:crypto/sm3" -import crypto_util "core:crypto/util" import x25519 "core:crypto/x25519" import pe "core:debug/pe" @@ -150,7 +149,6 @@ _ :: sha2 _ :: sha3 _ :: shake _ :: sm3 -_ :: crypto_util _ :: x25519 _ :: pe _ :: dynlib From b71afdc3ee8648def5de5b8df72e8e25790217f6 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 01:13:27 +0900 Subject: [PATCH 102/160] core/crypto/sha2: Refactor update/final This is largely modeled off the SM3 versions of these routines, since the relevant parts of the code are the same between SHA-256 and SM3, and the alterations required to support SHA-512 are relatively simple. The prior versions of update and the transform would leak memory, and doing things this way also reduces the context buffer sizes by 1 block. --- core/crypto/sha2/sha2.odin | 154 +++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 76 deletions(-) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index d4b6b87bb..024e52623 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -14,7 +14,6 @@ package sha2 import "core:encoding/endian" import "core:io" import "core:math/bits" -import "core:mem" import "core:os" /* @@ -482,8 +481,8 @@ init :: proc(ctx: ^$T) { } } - ctx.tot_len = 0 ctx.length = 0 + ctx.bitlength = 0 ctx.is_initialized = true } @@ -491,65 +490,72 @@ init :: proc(ctx: ^$T) { update :: proc(ctx: ^$T, data: []byte) { assert(ctx.is_initialized) - length := uint(len(data)) - block_nb: uint - new_len, rem_len, tmp_len: uint - shifted_message := make([]byte, length) - when T == Sha256_Context { CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE } else when T == Sha512_Context { CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE } - tmp_len = CURR_BLOCK_SIZE - ctx.length - rem_len = length < tmp_len ? length : tmp_len - copy(ctx.block[ctx.length:], data[:rem_len]) + data := data + ctx.length += u64(len(data)) - if ctx.length + length < CURR_BLOCK_SIZE { - ctx.length += length - return + if ctx.bitlength > 0 { + n := copy(ctx.block[ctx.bitlength:], data[:]) + ctx.bitlength += u64(n) + if ctx.bitlength == CURR_BLOCK_SIZE { + sha2_transf(ctx, ctx.block[:]) + ctx.bitlength = 0 + } + data = data[n:] } - - new_len = length - rem_len - block_nb = new_len / CURR_BLOCK_SIZE - shifted_message = data[rem_len:] - - sha2_transf(ctx, ctx.block[:], 1) - sha2_transf(ctx, shifted_message, block_nb) - - rem_len = new_len % CURR_BLOCK_SIZE - if rem_len > 0 { - when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])} else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])} + if len(data) >= CURR_BLOCK_SIZE { + n := len(data) &~ (CURR_BLOCK_SIZE - 1) + sha2_transf(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.bitlength = u64(copy(ctx.block[:], data[:])) } - - ctx.length = rem_len - when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6} else when T == Sha512_Context {ctx.tot_len += (block_nb + 1) << 7} } final :: proc(ctx: ^$T, hash: []byte) { assert(ctx.is_initialized) - block_nb, pm_len: uint - len_b: u64 - if len(hash) * 8 < ctx.md_bits { panic("crypto/sha2: invalid destination digest size") } - when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} + length := ctx.length - when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} + raw_pad: [SHA512_BLOCK_SIZE]byte + when T == Sha256_Context { + CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE + pm_len := 8 // 64-bits for length + } else when T == Sha512_Context { + CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE + pm_len := 16 // 128-bits for length + } + pad := raw_pad[:CURR_BLOCK_SIZE] + pad_len := u64(CURR_BLOCK_SIZE - pm_len) - len_b = u64(ctx.tot_len + ctx.length) << 3 - when T == Sha256_Context {pm_len = block_nb << 6} else when T == Sha512_Context {pm_len = block_nb << 7} + pad[0] = 0x80 + if length % CURR_BLOCK_SIZE < pad_len { + update(ctx, pad[0:pad_len - length % CURR_BLOCK_SIZE]) + } else { + update(ctx, pad[0:CURR_BLOCK_SIZE + pad_len - length % CURR_BLOCK_SIZE]) + } - mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(pm_len - ctx.length)) - ctx.block[ctx.length] = 0x80 - - endian.unchecked_put_u64be(ctx.block[pm_len - 8:], len_b) - - sha2_transf(ctx, ctx.block[:], block_nb) + length_hi, length_lo := bits.mul_u64(length, 8) // Length in bits + when T == Sha256_Context { + _ = length_hi + endian.unchecked_put_u64be(pad[:], length_lo) + update(ctx, pad[:8]) + } else when T == Sha512_Context { + endian.unchecked_put_u64be(pad[:], length_hi) + endian.unchecked_put_u64be(pad[8:], length_lo) + update(ctx, pad[0:16]) + } + assert(ctx.bitlength == 0) when T == Sha256_Context { for i := 0; i < ctx.md_bits / 32; i += 1 { @@ -572,21 +578,21 @@ SHA256_BLOCK_SIZE :: 64 SHA512_BLOCK_SIZE :: 128 Sha256_Context :: struct { - tot_len: uint, - length: uint, - block: [128]byte, - h: [8]u32, - md_bits: int, + block: [SHA256_BLOCK_SIZE]byte, + h: [8]u32, + bitlength: u64, + length: u64, + md_bits: int, is_initialized: bool, } Sha512_Context :: struct { - tot_len: uint, - length: uint, - block: [256]byte, - h: [8]u64, - md_bits: int, + block: [SHA512_BLOCK_SIZE]byte, + h: [8]u64, + bitlength: u64, + length: u64, + md_bits: int, is_initialized: bool, } @@ -716,52 +722,46 @@ SHA512_F4 :: #force_inline proc "contextless" (x: u64) -> u64 { } @(private) -sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { +sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { when T == Sha256_Context { w: [64]u32 wv: [8]u32 t1, t2: u32 + CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE } else when T == Sha512_Context { w: [80]u64 wv: [8]u64 t1, t2: u64 + CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE } - sub_block := make([]byte, len(data)) - i, j: i32 - - for i = 0; i < i32(block_nb); i += 1 { - when T == Sha256_Context { - sub_block = data[i << 6:] - } else when T == Sha512_Context { - sub_block = data[i << 7:] - } - - for j = 0; j < 16; j += 1 { + data := data + for len(data) >= CURR_BLOCK_SIZE { + for i := 0; i < 16; i += 1 { when T == Sha256_Context { - w[j] = endian.unchecked_get_u32be(sub_block[j << 2:]) + w[i] = endian.unchecked_get_u32be(data[i * 4:]) } else when T == Sha512_Context { - w[j] = endian.unchecked_get_u64be(sub_block[j << 3:]) + w[i] = endian.unchecked_get_u64be(data[i * 8:]) } } when T == Sha256_Context { - for j = 16; j < 64; j += 1 { - w[j] = SHA256_F4(w[j - 2]) + w[j - 7] + SHA256_F3(w[j - 15]) + w[j - 16] + for i := 16; i < 64; i += 1 { + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16] } } else when T == Sha512_Context { - for j = 16; j < 80; j += 1 { - w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16] + for i := 16; i < 80; i += 1 { + w[i] = SHA512_F4(w[i - 2]) + w[i - 7] + SHA512_F3(w[i - 15]) + w[i - 16] } } - for j = 0; j < 8; j += 1 { - wv[j] = ctx.h[j] + for i := 0; i < 8; i += 1 { + wv[i] = ctx.h[i] } when T == Sha256_Context { - for j = 0; j < 64; j += 1 { - t1 = wv[7] + SHA256_F2(wv[4]) + SHA256_CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j] + for i := 0; i < 64; i += 1 { + t1 = wv[7] + SHA256_F2(wv[4]) + SHA256_CH(wv[4], wv[5], wv[6]) + sha256_k[i] + w[i] t2 = SHA256_F1(wv[0]) + SHA256_MAJ(wv[0], wv[1], wv[2]) wv[7] = wv[6] wv[6] = wv[5] @@ -773,8 +773,8 @@ sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { wv[0] = t1 + t2 } } else when T == Sha512_Context { - for j = 0; j < 80; j += 1 { - t1 = wv[7] + SHA512_F2(wv[4]) + SHA512_CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j] + for i := 0; i < 80; i += 1 { + t1 = wv[7] + SHA512_F2(wv[4]) + SHA512_CH(wv[4], wv[5], wv[6]) + sha512_k[i] + w[i] t2 = SHA512_F1(wv[0]) + SHA512_MAJ(wv[0], wv[1], wv[2]) wv[7] = wv[6] wv[6] = wv[5] @@ -787,8 +787,10 @@ sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { } } - for j = 0; j < 8; j += 1 { - ctx.h[j] += wv[j] + for i := 0; i < 8; i += 1 { + ctx.h[i] += wv[i] } + + data = data[CURR_BLOCK_SIZE:] } } From aa821991b81fc7e8222347fbd0130e80478a4339 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 16:27:58 +0900 Subject: [PATCH 103/160] core/crypto/blake2: API cleanup and bug fixes - blake2s.Blake2s_Context -> blake2s.Context - blake2b.Blake2b_Context -> blake2b.Context - Fix the BLAKE2s low level API (context type was incorrect) - Support the configurable output size --- core/crypto/_blake2/blake2.odin | 24 ++++++++++++------- core/crypto/blake2b/blake2b.odin | 35 +++++++++++++-------------- core/crypto/blake2s/blake2s.odin | 35 +++++++++++++-------------- vendor/botan/blake2b/blake2b.odin | 39 ++++++++++++++----------------- 4 files changed, 70 insertions(+), 63 deletions(-) diff --git a/core/crypto/_blake2/blake2.odin b/core/crypto/_blake2/blake2.odin index ce6f88f20..13b58dba9 100644 --- a/core/crypto/_blake2/blake2.odin +++ b/core/crypto/_blake2/blake2.odin @@ -86,8 +86,14 @@ BLAKE2B_IV := [8]u64 { init :: proc(ctx: ^$T) { when T == Blake2s_Context { block_size :: BLAKE2S_BLOCK_SIZE + max_size :: BLAKE2S_SIZE } else when T == Blake2b_Context { block_size :: BLAKE2B_BLOCK_SIZE + max_size :: BLAKE2B_SIZE + } + + if ctx.cfg.size > max_size { + panic("blake2: requested output size exceeeds algorithm max") } p := make([]byte, block_size) @@ -192,13 +198,12 @@ final :: proc(ctx: ^$T, hash: []byte) { assert(ctx.is_initialized) when T == Blake2s_Context { - if len(hash) < BLAKE2S_SIZE { + if len(hash) < int(ctx.cfg.size) { panic("crypto/blake2s: invalid destination digest size") } blake2s_final(ctx, hash) - } - when T == Blake2b_Context { - if len(hash) < BLAKE2B_SIZE { + } else when T == Blake2b_Context { + if len(hash) < int(ctx.cfg.size) { panic("crypto/blake2b: invalid destination digest size") } blake2b_final(ctx, hash) @@ -228,9 +233,11 @@ blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) { blocks(ctx, ctx.x[:]) + dst: [BLAKE2S_SIZE]byte for i := 0; i < BLAKE2S_SIZE / 4; i += 1 { - endian.unchecked_put_u32le(hash[i * 4:], ctx.h[i]) + endian.unchecked_put_u32le(dst[i * 4:], ctx.h[i]) } + copy(hash, dst[:]) } @(private) @@ -254,17 +261,18 @@ blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) { blocks(ctx, ctx.x[:]) + dst: [BLAKE2B_SIZE]byte for i := 0; i < BLAKE2B_SIZE / 8; i += 1 { - endian.unchecked_put_u64le(hash[i * 8:], ctx.h[i]) + endian.unchecked_put_u64le(dst[i * 8:], ctx.h[i]) } + copy(hash, dst[:]) } @(private) blocks :: proc "contextless" (ctx: ^$T, p: []byte) { when T == Blake2s_Context { blake2s_blocks(ctx, p) - } - when T == Blake2b_Context { + } else when T == Blake2b_Context { blake2b_blocks(ctx, p) } } diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index 476ecdeeb..17657311e 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -32,13 +32,13 @@ hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2b_Context + ctx: Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2B_SIZE ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -53,35 +53,36 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - ctx: _blake2.Blake2b_Context + ctx: Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2B_SIZE ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } - // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2b_Context + ctx: Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2B_SIZE ctx.cfg = cfg - _blake2.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _blake2.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _blake2.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -111,16 +112,16 @@ hash :: proc { Low level API */ -Blake2b_Context :: _blake2.Blake2b_Context +Context :: _blake2.Blake2b_Context -init :: proc(ctx: ^_blake2.Blake2b_Context) { +init :: proc(ctx: ^Context) { _blake2.init(ctx) } -update :: proc(ctx: ^_blake2.Blake2b_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { _blake2.update(ctx, data) } -final :: proc(ctx: ^_blake2.Blake2b_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { _blake2.final(ctx, hash) } diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index f4d8eb804..2da619bb8 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -32,17 +32,16 @@ hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2s_Context + ctx: Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2S_SIZE ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } - // hash_string_to_buffer will hash the given input and assign the // computed hash to the second parameter. // It requires that the destination buffer is at least as big as the digest size @@ -54,34 +53,36 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - ctx: _blake2.Blake2s_Context + ctx: Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2S_SIZE ctx.cfg = cfg - _blake2.init(&ctx) - _blake2.update(&ctx, data) - _blake2.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: _blake2.Blake2s_Context + ctx: Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2S_SIZE ctx.cfg = cfg - _blake2.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _blake2.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _blake2.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -111,16 +112,16 @@ hash :: proc { Low level API */ -Blake2s_Context :: _blake2.Blake2b_Context +Context :: _blake2.Blake2s_Context -init :: proc(ctx: ^_blake2.Blake2s_Context) { +init :: proc(ctx: ^Context) { _blake2.init(ctx) } -update :: proc(ctx: ^_blake2.Blake2s_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { _blake2.update(ctx, data) } -final :: proc(ctx: ^_blake2.Blake2s_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { _blake2.final(ctx, hash) } diff --git a/vendor/botan/blake2b/blake2b.odin b/vendor/botan/blake2b/blake2b.odin index 6cc828caf..277a33ada 100644 --- a/vendor/botan/blake2b/blake2b.odin +++ b/vendor/botan/blake2b/blake2b.odin @@ -32,11 +32,10 @@ hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_BLAKE2B, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -52,31 +51,29 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_BLAKE2B, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_BLAKE2B, 0) + ctx: Context + init(&ctx) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle @@ -105,17 +102,17 @@ hash :: proc { Low level API */ -Blake2b_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t) { +init :: proc "contextless" (ctx: ^Context) { botan.hash_init(ctx, botan.HASH_BLAKE2B, 0) } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } From 841e73fcd5ed9ebca7ebf27a5a8c489c91e36517 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 16:39:48 +0900 Subject: [PATCH 104/160] core/crypto/keccak: API cleanup - keccak.Keccak_Context -> keccak.Context --- core/crypto/keccak/keccak.odin | 113 +++++++++++++++++--------------- vendor/botan/keccak/keccak.odin | 39 +++++------ 2 files changed, 78 insertions(+), 74 deletions(-) diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index b8a071e8f..a41befd6d 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -16,7 +16,6 @@ import "core:os" import "../_sha3" - /* High level API */ @@ -36,12 +35,12 @@ hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_224 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -56,32 +55,34 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_224 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_224 ctx.is_keccak = true - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -117,12 +118,12 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -137,32 +138,34 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 ctx.is_keccak = true - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -198,12 +201,12 @@ hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_384 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -218,32 +221,34 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_384 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_384 ctx.is_keccak = true - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -279,12 +284,12 @@ hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_512 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -299,32 +304,34 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_512 ctx.is_keccak = true - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_512 ctx.is_keccak = true - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -354,17 +361,17 @@ hash_512 :: proc { Low level API */ -Keccak_Context :: _sha3.Sha3_Context +Context :: _sha3.Sha3_Context -init :: proc(ctx: ^_sha3.Sha3_Context) { +init :: proc(ctx: ^Context) { ctx.is_keccak = true _sha3.init(ctx) } -update :: proc(ctx: ^_sha3.Sha3_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { _sha3.update(ctx, data) } -final :: proc(ctx: ^_sha3.Sha3_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { _sha3.final(ctx, hash) } diff --git a/vendor/botan/keccak/keccak.odin b/vendor/botan/keccak/keccak.odin index c08eaf598..1d08f427d 100644 --- a/vendor/botan/keccak/keccak.odin +++ b/vendor/botan/keccak/keccak.odin @@ -32,11 +32,10 @@ hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_KECCAK_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -52,31 +51,29 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_KECCAK_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_KECCAK_512, 0) + ctx: Context + init(&ctx) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle @@ -105,17 +102,17 @@ hash_512 :: proc { Low level API */ -Keccak_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t) { +init :: proc "contextless" (ctx: ^Context) { botan.hash_init(ctx, botan.HASH_KECCAK_512, 0) } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } From e819eebc63b5738eb61c284498dde84deba1777f Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 16:48:00 +0900 Subject: [PATCH 105/160] core/crypto/md5: API cleanup - md5.Md5_Context -> md5.Context --- core/crypto/md5/md5.odin | 18 ++++++++++-------- vendor/botan/md5/md5.odin | 39 ++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index 441e15a64..69ae087e4 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -32,7 +32,7 @@ hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: Md5_Context + ctx: Context init(&ctx) update(&ctx, data) final(&ctx, hash[:]) @@ -50,7 +50,7 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - ctx: Md5_Context + ctx: Context init(&ctx) update(&ctx, data) final(&ctx, hash) @@ -60,10 +60,12 @@ hash_bytes_to_buffer :: proc(data, hash: []byte) { // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: Md5_Context + ctx: Context init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -101,7 +103,7 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^Md5_Context) { +init :: proc(ctx: ^Context) { ctx.state[0] = 0x67452301 ctx.state[1] = 0xefcdab89 ctx.state[2] = 0x98badcfe @@ -113,7 +115,7 @@ init :: proc(ctx: ^Md5_Context) { ctx.is_initialized = true } -update :: proc(ctx: ^Md5_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { assert(ctx.is_initialized) for i := 0; i < len(data); i += 1 { @@ -127,7 +129,7 @@ update :: proc(ctx: ^Md5_Context, data: []byte) { } } -final :: proc(ctx: ^Md5_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { assert(ctx.is_initialized) if len(hash) < DIGEST_SIZE { @@ -171,7 +173,7 @@ final :: proc(ctx: ^Md5_Context, hash: []byte) { BLOCK_SIZE :: 64 -Md5_Context :: struct { +Context :: struct { data: [BLOCK_SIZE]byte, state: [4]u32, bitlen: u64, @@ -206,7 +208,7 @@ II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u } @(private) -transform :: proc "contextless" (ctx: ^Md5_Context, data: []byte) { +transform :: proc "contextless" (ctx: ^Context, data: []byte) { m: [DIGEST_SIZE]u32 for i := 0; i < DIGEST_SIZE; i += 1 { diff --git a/vendor/botan/md5/md5.odin b/vendor/botan/md5/md5.odin index 9aaf96d27..c2ed7c45c 100644 --- a/vendor/botan/md5/md5.odin +++ b/vendor/botan/md5/md5.odin @@ -32,11 +32,10 @@ hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_MD5, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -52,31 +51,29 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_MD5, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_MD5, 0) + ctx: Context + init(&ctx) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle @@ -105,17 +102,17 @@ hash :: proc { Low level API */ -Md5_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t) { +init :: proc "contextless" (ctx: ^Context) { botan.hash_init(ctx, botan.HASH_MD5, 0) } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } From 506adfb10535f3b9ff2bc0f9f443aa7237ff478b Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 16:53:01 +0900 Subject: [PATCH 106/160] core/crypto/sha1: API cleanup -sha1.Sha1_Context -> Context --- core/crypto/sha1/sha1.odin | 18 +++++++++-------- vendor/botan/sha1/sha1.odin | 39 +++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index e6da5b6b9..6c4407067 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -32,7 +32,7 @@ hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: Sha1_Context + ctx: Context init(&ctx) update(&ctx, data) final(&ctx, hash[:]) @@ -50,7 +50,7 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - ctx: Sha1_Context + ctx: Context init(&ctx) update(&ctx, data) final(&ctx, hash) @@ -60,10 +60,12 @@ hash_bytes_to_buffer :: proc(data, hash: []byte) { // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: Sha1_Context + ctx: Context init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -101,7 +103,7 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^Sha1_Context) { +init :: proc(ctx: ^Context) { ctx.state[0] = 0x67452301 ctx.state[1] = 0xefcdab89 ctx.state[2] = 0x98badcfe @@ -118,7 +120,7 @@ init :: proc(ctx: ^Sha1_Context) { ctx.is_initialized = true } -update :: proc(ctx: ^Sha1_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { assert(ctx.is_initialized) for i := 0; i < len(data); i += 1 { @@ -132,7 +134,7 @@ update :: proc(ctx: ^Sha1_Context, data: []byte) { } } -final :: proc(ctx: ^Sha1_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { assert(ctx.is_initialized) if len(hash) < DIGEST_SIZE { @@ -176,7 +178,7 @@ final :: proc(ctx: ^Sha1_Context, hash: []byte) { BLOCK_SIZE :: 64 -Sha1_Context :: struct { +Context :: struct { data: [BLOCK_SIZE]byte, datalen: u32, bitlen: u64, @@ -187,7 +189,7 @@ Sha1_Context :: struct { } @(private) -transform :: proc "contextless" (ctx: ^Sha1_Context, data: []byte) { +transform :: proc "contextless" (ctx: ^Context, data: []byte) { a, b, c, d, e, i, t: u32 m: [80]u32 diff --git a/vendor/botan/sha1/sha1.odin b/vendor/botan/sha1/sha1.odin index c39a41d0a..929f4c0be 100644 --- a/vendor/botan/sha1/sha1.odin +++ b/vendor/botan/sha1/sha1.odin @@ -32,11 +32,10 @@ hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA1, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -52,31 +51,29 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA1, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA1, 0) + ctx: Context + init(&ctx) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle @@ -105,17 +102,17 @@ hash :: proc { Low level API */ -Sha1_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t) { +init :: proc "contextless" (ctx: ^Context) { botan.hash_init(ctx, botan.HASH_SHA1, 0) } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } From 92aad90c6bfbbacb7aa73c588f3fc17e8fbb8b67 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 17:07:32 +0900 Subject: [PATCH 107/160] core/crypto/sha2: API cleanup - sha2.Sha256_Context -> sha2.Context_256 - sha2.Sha512_Context -> sha2.Context_512 --- core/crypto/sha2/sha2.odin | 80 ++++++++++++---------- vendor/botan/sha2/sha2.odin | 132 ++++++++++++++++-------------------- 2 files changed, 105 insertions(+), 107 deletions(-) diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 024e52623..10ac73ab6 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -36,7 +36,7 @@ hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { hash: [DIGEST_SIZE_224]byte - ctx: Sha256_Context + ctx: Context_256 ctx.md_bits = 224 init(&ctx) update(&ctx, data) @@ -55,7 +55,7 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - ctx: Sha256_Context + ctx: Context_256 ctx.md_bits = 224 init(&ctx) update(&ctx, data) @@ -66,11 +66,13 @@ hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { hash: [DIGEST_SIZE_224]byte - ctx: Sha256_Context + ctx: Context_256 ctx.md_bits = 224 init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -114,7 +116,7 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte - ctx: Sha256_Context + ctx: Context_256 ctx.md_bits = 256 init(&ctx) update(&ctx, data) @@ -133,7 +135,7 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - ctx: Sha256_Context + ctx: Context_256 ctx.md_bits = 256 init(&ctx) update(&ctx, data) @@ -144,11 +146,13 @@ hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: Sha256_Context + ctx: Context_256 ctx.md_bits = 256 init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -192,7 +196,7 @@ hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { hash: [DIGEST_SIZE_384]byte - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 384 init(&ctx) update(&ctx, data) @@ -211,7 +215,7 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 384 init(&ctx) update(&ctx, data) @@ -222,11 +226,13 @@ hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { hash: [DIGEST_SIZE_384]byte - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 384 init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -270,7 +276,7 @@ hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { hash: [DIGEST_SIZE_512]byte - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 512 init(&ctx) update(&ctx, data) @@ -289,7 +295,7 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 512 init(&ctx) update(&ctx, data) @@ -300,11 +306,13 @@ hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { hash: [DIGEST_SIZE_512]byte - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 512 init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -348,7 +356,7 @@ hash_string_512_256 :: proc(data: string) -> [DIGEST_SIZE_512_256]byte { // computed hash hash_bytes_512_256 :: proc(data: []byte) -> [DIGEST_SIZE_512_256]byte { hash: [DIGEST_SIZE_512_256]byte - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 256 init(&ctx) update(&ctx, data) @@ -367,7 +375,7 @@ hash_string_to_buffer_512_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512_256 :: proc(data, hash: []byte) { - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 256 init(&ctx) update(&ctx, data) @@ -378,11 +386,13 @@ hash_bytes_to_buffer_512_256 :: proc(data, hash: []byte) { // hash from its contents hash_stream_512_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512_256]byte, bool) { hash: [DIGEST_SIZE_512_256]byte - ctx: Sha512_Context + ctx: Context_512 ctx.md_bits = 256 init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -421,7 +431,7 @@ hash_512_256 :: proc { */ init :: proc(ctx: ^$T) { - when T == Sha256_Context { + when T == Context_256 { switch ctx.md_bits { case 224: ctx.h[0] = 0xc1059ed8 @@ -444,7 +454,7 @@ init :: proc(ctx: ^$T) { case: panic("crypto/sha2: invalid digest output length") } - } else when T == Sha512_Context { + } else when T == Context_512 { switch ctx.md_bits { case 256: // SHA-512/256 @@ -490,9 +500,9 @@ init :: proc(ctx: ^$T) { update :: proc(ctx: ^$T, data: []byte) { assert(ctx.is_initialized) - when T == Sha256_Context { + when T == Context_256 { CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE - } else when T == Sha512_Context { + } else when T == Context_512 { CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE } @@ -528,10 +538,10 @@ final :: proc(ctx: ^$T, hash: []byte) { length := ctx.length raw_pad: [SHA512_BLOCK_SIZE]byte - when T == Sha256_Context { + when T == Context_256 { CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE pm_len := 8 // 64-bits for length - } else when T == Sha512_Context { + } else when T == Context_512 { CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE pm_len := 16 // 128-bits for length } @@ -546,22 +556,22 @@ final :: proc(ctx: ^$T, hash: []byte) { } length_hi, length_lo := bits.mul_u64(length, 8) // Length in bits - when T == Sha256_Context { + when T == Context_256 { _ = length_hi endian.unchecked_put_u64be(pad[:], length_lo) update(ctx, pad[:8]) - } else when T == Sha512_Context { + } else when T == Context_512 { endian.unchecked_put_u64be(pad[:], length_hi) endian.unchecked_put_u64be(pad[8:], length_lo) update(ctx, pad[0:16]) } assert(ctx.bitlength == 0) - when T == Sha256_Context { + when T == Context_256 { for i := 0; i < ctx.md_bits / 32; i += 1 { endian.unchecked_put_u32be(hash[i * 4:], ctx.h[i]) } - } else when T == Sha512_Context { + } else when T == Context_512 { for i := 0; i < ctx.md_bits / 64; i += 1 { endian.unchecked_put_u64be(hash[i * 8:], ctx.h[i]) } @@ -577,7 +587,7 @@ final :: proc(ctx: ^$T, hash: []byte) { SHA256_BLOCK_SIZE :: 64 SHA512_BLOCK_SIZE :: 128 -Sha256_Context :: struct { +Context_256 :: struct { block: [SHA256_BLOCK_SIZE]byte, h: [8]u32, bitlength: u64, @@ -587,7 +597,7 @@ Sha256_Context :: struct { is_initialized: bool, } -Sha512_Context :: struct { +Context_512 :: struct { block: [SHA512_BLOCK_SIZE]byte, h: [8]u64, bitlength: u64, @@ -723,12 +733,12 @@ SHA512_F4 :: #force_inline proc "contextless" (x: u64) -> u64 { @(private) sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { - when T == Sha256_Context { + when T == Context_256 { w: [64]u32 wv: [8]u32 t1, t2: u32 CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE - } else when T == Sha512_Context { + } else when T == Context_512 { w: [80]u64 wv: [8]u64 t1, t2: u64 @@ -738,18 +748,18 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { data := data for len(data) >= CURR_BLOCK_SIZE { for i := 0; i < 16; i += 1 { - when T == Sha256_Context { + when T == Context_256 { w[i] = endian.unchecked_get_u32be(data[i * 4:]) - } else when T == Sha512_Context { + } else when T == Context_512 { w[i] = endian.unchecked_get_u64be(data[i * 8:]) } } - when T == Sha256_Context { + when T == Context_256 { for i := 16; i < 64; i += 1 { w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16] } - } else when T == Sha512_Context { + } else when T == Context_512 { for i := 16; i < 80; i += 1 { w[i] = SHA512_F4(w[i - 2]) + w[i - 7] + SHA512_F3(w[i - 15]) + w[i - 16] } @@ -759,7 +769,7 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { wv[i] = ctx.h[i] } - when T == Sha256_Context { + when T == Context_256 { for i := 0; i < 64; i += 1 { t1 = wv[7] + SHA256_F2(wv[4]) + SHA256_CH(wv[4], wv[5], wv[6]) + sha256_k[i] + w[i] t2 = SHA256_F1(wv[0]) + SHA256_MAJ(wv[0], wv[1], wv[2]) @@ -772,7 +782,7 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { wv[1] = wv[0] wv[0] = t1 + t2 } - } else when T == Sha512_Context { + } else when T == Context_512 { for i := 0; i < 80; i += 1 { t1 = wv[7] + SHA512_F2(wv[4]) + SHA512_CH(wv[4], wv[5], wv[6]) + sha512_k[i] + w[i] t2 = SHA512_F1(wv[0]) + SHA512_MAJ(wv[0], wv[1], wv[2]) diff --git a/vendor/botan/sha2/sha2.odin b/vendor/botan/sha2/sha2.odin index 4ce001a75..66c6b97df 100644 --- a/vendor/botan/sha2/sha2.odin +++ b/vendor/botan/sha2/sha2.odin @@ -35,11 +35,10 @@ hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { hash: [DIGEST_SIZE_224]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_224, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 224) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -55,31 +54,29 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_224, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 224) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { hash: [DIGEST_SIZE_224]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_224, 0) + ctx: Context + init(&ctx, hash_size = 224) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle @@ -114,11 +111,10 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 256) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -134,31 +130,29 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 256) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_256, 0) + ctx: Context + init(&ctx, hash_size = 256) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle @@ -193,11 +187,10 @@ hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { hash: [DIGEST_SIZE_384]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_384, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 384) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -213,31 +206,29 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_384, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 384) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { hash: [DIGEST_SIZE_384]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_384, 0) + ctx: Context + init(&ctx, hash_size = 384) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle @@ -272,11 +263,10 @@ hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 512) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -292,31 +282,29 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 512) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA_512, 0) + ctx: Context + init(&ctx, hash_size = 512) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle @@ -345,9 +333,9 @@ hash_512 :: proc { Low level API */ -Sha2_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t, hash_size := 512) { +init :: proc "contextless" (ctx: ^Context, hash_size := 512) { switch hash_size { case 224: botan.hash_init(ctx, botan.HASH_SHA_224, 0) case 256: botan.hash_init(ctx, botan.HASH_SHA_256, 0) @@ -356,11 +344,11 @@ init :: proc "contextless" (ctx: ^botan.hash_t, hash_size := 512) { } } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } \ No newline at end of file From b8f9deb3d841d564f4b6fd30db6831ef238d8821 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 17:18:01 +0900 Subject: [PATCH 108/160] core/crypto/sha3: API cleanup - sha3.Sha3_Context -> sha3.Context --- core/crypto/sha3/sha3.odin | 112 ++++++++++++++++-------------- vendor/botan/sha3/sha3.odin | 132 ++++++++++++++++-------------------- 2 files changed, 120 insertions(+), 124 deletions(-) diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 10a65e0b1..f91baad3d 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -35,11 +35,11 @@ hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_224 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -54,30 +54,32 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_224 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { hash: [DIGEST_SIZE_224]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_224 - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -113,11 +115,11 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -132,30 +134,32 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -191,11 +195,11 @@ hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_384 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -210,30 +214,32 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_384 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { hash: [DIGEST_SIZE_384]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_384 - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -269,11 +275,11 @@ hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_512 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -288,30 +294,32 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_512 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.final(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { hash: [DIGEST_SIZE_512]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_512 - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.final(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -341,16 +349,16 @@ hash_512 :: proc { Low level API */ -Sha3_Context :: _sha3.Sha3_Context +Context :: _sha3.Sha3_Context -init :: proc(ctx: ^_sha3.Sha3_Context) { +init :: proc(ctx: ^Context) { _sha3.init(ctx) } -update :: proc(ctx: ^_sha3.Sha3_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { _sha3.update(ctx, data) } -final :: proc(ctx: ^_sha3.Sha3_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { _sha3.final(ctx, hash) } diff --git a/vendor/botan/sha3/sha3.odin b/vendor/botan/sha3/sha3.odin index 5dcb008ce..dbe28dae4 100644 --- a/vendor/botan/sha3/sha3.odin +++ b/vendor/botan/sha3/sha3.odin @@ -35,11 +35,10 @@ hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { // computed hash hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { hash: [DIGEST_SIZE_224]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_224, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 224) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -55,31 +54,29 @@ hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_224, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 224) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { hash: [DIGEST_SIZE_224]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_224, 0) + ctx: Context + init(&ctx, hash_size = 224) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle @@ -114,11 +111,10 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 256) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -134,31 +130,29 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 256) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_256, 0) + ctx: Context + init(&ctx, hash_size = 256) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle @@ -193,11 +187,10 @@ hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { // computed hash hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { hash: [DIGEST_SIZE_384]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_384, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 384) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -213,31 +206,29 @@ hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_384, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 384) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { hash: [DIGEST_SIZE_384]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_384, 0) + ctx: Context + init(&ctx, hash_size = 384) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle @@ -272,11 +263,10 @@ hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { // computed hash hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 512) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -292,31 +282,29 @@ hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_512, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 512) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { hash: [DIGEST_SIZE_512]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHA3_512, 0) + ctx: Context + init(&ctx, hash_size = 512) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle @@ -345,9 +333,9 @@ hash_512 :: proc { Low level API */ -Sha3_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t, hash_size := 512) { +init :: proc "contextless" (ctx: ^Context, hash_size := 512) { switch hash_size { case 224: botan.hash_init(ctx, botan.HASH_SHA3_224, 0) case 256: botan.hash_init(ctx, botan.HASH_SHA3_256, 0) @@ -356,11 +344,11 @@ init :: proc "contextless" (ctx: ^botan.hash_t, hash_size := 512) { } } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } \ No newline at end of file From 7640fb0483224b4c7a9bfa55fac3203de3f3e5dc Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 17:27:14 +0900 Subject: [PATCH 109/160] core/crypto/shake: API cleanup - shake.Shake_Context -> shake.Context --- core/crypto/shake/shake.odin | 66 ++++++++++++++++----------------- vendor/botan/shake/shake.odin | 70 ++++++++++++++++------------------- 2 files changed, 64 insertions(+), 72 deletions(-) diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index c490de41e..e4b4c1e31 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -36,12 +36,11 @@ hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { // computed hash hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { hash: [DIGEST_SIZE_128]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_128 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -56,32 +55,32 @@ hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_128 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_128 will read the stream in chunks and compute a // hash from its contents hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { hash: [DIGEST_SIZE_128]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_128 - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -117,12 +116,11 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -137,32 +135,32 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) - _sha3.update(&ctx, data) - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash) + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: _sha3.Sha3_Context + ctx: Context ctx.mdlen = DIGEST_SIZE_256 - _sha3.init(&ctx) + init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) if read > 0 { - _sha3.update(&ctx, buf[:read]) + update(&ctx, buf[:read]) } } - _sha3.shake_xof(&ctx) - _sha3.shake_out(&ctx, hash[:]) + final(&ctx, hash[:]) return hash, true } @@ -192,17 +190,17 @@ hash_256 :: proc { Low level API */ -Shake_Context :: _sha3.Sha3_Context +Context :: _sha3.Sha3_Context -init :: proc(ctx: ^_sha3.Sha3_Context) { +init :: proc(ctx: ^Context) { _sha3.init(ctx) } -update :: proc(ctx: ^_sha3.Sha3_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { _sha3.update(ctx, data) } -final :: proc(ctx: ^_sha3.Sha3_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { _sha3.shake_xof(ctx) _sha3.shake_out(ctx, hash[:]) } diff --git a/vendor/botan/shake/shake.odin b/vendor/botan/shake/shake.odin index af577f316..fe059f0f9 100644 --- a/vendor/botan/shake/shake.odin +++ b/vendor/botan/shake/shake.odin @@ -33,11 +33,10 @@ hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { // computed hash hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { hash: [DIGEST_SIZE_128]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHAKE_128, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 128) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -53,31 +52,29 @@ hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHAKE_128, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 128) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_128 will read the stream in chunks and compute a // hash from its contents hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { hash: [DIGEST_SIZE_128]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHAKE_128, 0) + ctx: Context + init(&ctx, hash_size = 128) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_128 will read the file provided by the given handle @@ -112,11 +109,10 @@ hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { // computed hash hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHAKE_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 256) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -132,31 +128,29 @@ hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHAKE_256, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx, hash_size = 256) + update(&ctx, data) + final(&ctx, hash) } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { hash: [DIGEST_SIZE_256]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SHAKE_256, 0) + ctx: Context + init(&ctx, hash_size = 256) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle @@ -185,20 +179,20 @@ hash_256 :: proc { Low level API */ -Shake_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t, hash_size := 256) { +init :: proc "contextless" (ctx: ^Context, hash_size := 256) { switch hash_size { case 128: botan.hash_init(ctx, botan.HASH_SHAKE_128, 0) case 256: botan.hash_init(ctx, botan.HASH_SHAKE_256, 0) } } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } From 4587a55486a1c0367778c67fec50d895bf0dbd13 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 17:34:23 +0900 Subject: [PATCH 110/160] core/crypto/sm3: API cleanup - sm3.Sm3_Context -> sm3.Context --- core/crypto/sm3/sm3.odin | 18 ++++++++++-------- vendor/botan/sm3/sm3.odin | 39 ++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index 943172482..7a7a0b8a6 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -31,7 +31,7 @@ hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: Sm3_Context + ctx: Context init(&ctx) update(&ctx, data) final(&ctx, hash[:]) @@ -49,7 +49,7 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // computed hash into the second parameter. // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { - ctx: Sm3_Context + ctx: Context init(&ctx) update(&ctx, data) final(&ctx, hash) @@ -59,10 +59,12 @@ hash_bytes_to_buffer :: proc(data, hash: []byte) { // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: Sm3_Context + ctx: Context init(&ctx) + buf := make([]byte, 512) defer delete(buf) + read := 1 for read > 0 { read, _ = io.read(s, buf) @@ -100,7 +102,7 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^Sm3_Context) { +init :: proc(ctx: ^Context) { ctx.state[0] = IV[0] ctx.state[1] = IV[1] ctx.state[2] = IV[2] @@ -116,7 +118,7 @@ init :: proc(ctx: ^Sm3_Context) { ctx.is_initialized = true } -update :: proc(ctx: ^Sm3_Context, data: []byte) { +update :: proc(ctx: ^Context, data: []byte) { assert(ctx.is_initialized) data := data @@ -141,7 +143,7 @@ update :: proc(ctx: ^Sm3_Context, data: []byte) { } } -final :: proc(ctx: ^Sm3_Context, hash: []byte) { +final :: proc(ctx: ^Context, hash: []byte) { assert(ctx.is_initialized) if len(hash) < DIGEST_SIZE { @@ -176,7 +178,7 @@ final :: proc(ctx: ^Sm3_Context, hash: []byte) { BLOCK_SIZE :: 64 -Sm3_Context :: struct { +Context :: struct { state: [8]u32, x: [BLOCK_SIZE]byte, bitlength: u64, @@ -192,7 +194,7 @@ IV := [8]u32 { } @(private) -block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { +block :: proc "contextless" (ctx: ^Context, buf: []byte) { buf := buf w: [68]u32 diff --git a/vendor/botan/sm3/sm3.odin b/vendor/botan/sm3/sm3.odin index dd6da9e63..961d4f3f9 100644 --- a/vendor/botan/sm3/sm3.odin +++ b/vendor/botan/sm3/sm3.odin @@ -32,11 +32,10 @@ hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { // computed hash hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SM3, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) return hash } @@ -52,31 +51,29 @@ hash_string_to_buffer :: proc(data: string, hash: []byte) { // It requires that the destination buffer is at least as big as the digest size hash_bytes_to_buffer :: proc(data, hash: []byte) { assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SM3, 0) - botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) + ctx: Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { hash: [DIGEST_SIZE]byte - ctx: botan.hash_t - botan.hash_init(&ctx, botan.HASH_SM3, 0) + ctx: Context + init(&ctx) buf := make([]byte, 512) defer delete(buf) i := 1 for i > 0 { i, _ = io.read(s, buf) if i > 0 { - botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i)) - } + update(&ctx, buf[:i]) + } } - botan.hash_final(ctx, &hash[0]) - botan.hash_destroy(ctx) - return hash, true + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle @@ -105,17 +102,17 @@ hash :: proc { Low level API */ -Sm3_Context :: botan.hash_t +Context :: botan.hash_t -init :: proc "contextless" (ctx: ^botan.hash_t) { +init :: proc "contextless" (ctx: ^Context) { botan.hash_init(ctx, botan.HASH_SM3, 0) } -update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data))) } -final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) { +final :: proc "contextless" (ctx: ^Context, hash: []byte) { botan.hash_final(ctx^, &hash[0]) botan.hash_destroy(ctx^) } \ No newline at end of file From 59950bcad6829d656fa58b1e1c10330535d2fef3 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 19:18:45 +0900 Subject: [PATCH 111/160] core/crypto: Exile keccak, md5 and sha1 to legacy In an perfect world these would just be removed, but the world is imperfect, and people are forced to interact/interface with things that are broken. --- core/crypto/README.md | 6 +++--- core/crypto/legacy/README.md | 10 ++++++++++ core/crypto/{ => legacy}/keccak/keccak.odin | 2 +- core/crypto/{ => legacy}/md5/md5.odin | 0 core/crypto/{ => legacy}/sha1/sha1.odin | 0 examples/all/all_main.odin | 6 +++--- examples/all/all_vendor.odin | 6 +++--- tests/core/crypto/test_core_crypto.odin | 6 +++--- tests/vendor/botan/test_vendor_botan.odin | 6 +++--- vendor/botan/README.md | 6 +++--- vendor/botan/legacy/README.md | 10 ++++++++++ vendor/botan/{ => legacy}/keccak/keccak.odin | 2 +- vendor/botan/{ => legacy}/md5/md5.odin | 2 +- vendor/botan/{ => legacy}/sha1/sha1.odin | 2 +- 14 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 core/crypto/legacy/README.md rename core/crypto/{ => legacy}/keccak/keccak.odin (99%) rename core/crypto/{ => legacy}/md5/md5.odin (100%) rename core/crypto/{ => legacy}/sha1/sha1.odin (100%) create mode 100644 vendor/botan/legacy/README.md rename vendor/botan/{ => legacy}/keccak/keccak.odin (99%) rename vendor/botan/{ => legacy}/md5/md5.odin (98%) rename vendor/botan/{ => legacy}/sha1/sha1.odin (98%) diff --git a/core/crypto/README.md b/core/crypto/README.md index 69f76b719..35ed9ca70 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -10,13 +10,13 @@ Please see the chart below for the options. |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | -| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | -| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | -| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | | [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | +| legacy/[Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | +| legacy/[MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | +| legacy/[SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | #### High level API Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*. diff --git a/core/crypto/legacy/README.md b/core/crypto/legacy/README.md new file mode 100644 index 000000000..e1ba6f54b --- /dev/null +++ b/core/crypto/legacy/README.md @@ -0,0 +1,10 @@ +# crypto/legacy + +These are algorithms that are shipped solely for the purpose of +interoperability with legacy systems. The use of these packages in +any other capacity is discouraged, especially those that are known +to be broken. + +- keccak - The draft version of the algorithm that became SHA-3 +- MD5 - Broken (https://eprint.iacr.org/2005/075) +- SHA-1 - Broken (https://eprint.iacr.org/2017/190) diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/legacy/keccak/keccak.odin similarity index 99% rename from core/crypto/keccak/keccak.odin rename to core/crypto/legacy/keccak/keccak.odin index a41befd6d..09db853a6 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/legacy/keccak/keccak.odin @@ -14,7 +14,7 @@ package keccak import "core:io" import "core:os" -import "../_sha3" +import "../../_sha3" /* High level API diff --git a/core/crypto/md5/md5.odin b/core/crypto/legacy/md5/md5.odin similarity index 100% rename from core/crypto/md5/md5.odin rename to core/crypto/legacy/md5/md5.odin diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/legacy/sha1/sha1.odin similarity index 100% rename from core/crypto/sha1/sha1.odin rename to core/crypto/legacy/sha1/sha1.odin diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index bdbaf0e6c..0872e0550 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -27,10 +27,10 @@ import blake2b "core:crypto/blake2b" import blake2s "core:crypto/blake2s" import chacha20 "core:crypto/chacha20" import chacha20poly1305 "core:crypto/chacha20poly1305" -import keccak "core:crypto/keccak" -import md5 "core:crypto/md5" +import keccak "core:crypto/legacy/keccak" +import md5 "core:crypto/legacy/md5" +import sha1 "core:crypto/legacy/sha1" import poly1305 "core:crypto/poly1305" -import sha1 "core:crypto/sha1" import sha2 "core:crypto/sha2" import sha3 "core:crypto/sha3" import shake "core:crypto/shake" diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index 075276c11..0e92c94bb 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -2,9 +2,9 @@ package all import botan_bindings "vendor:botan/bindings" import botan_blake2b "vendor:botan/blake2b" -import keccak "vendor:botan/keccak" -import md5 "vendor:botan/md5" -import sha1 "vendor:botan/sha1" +import keccak "vendor:botan/legacy/keccak" +import md5 "vendor:botan/legacy/md5" +import sha1 "vendor:botan/legacy/sha1" import sha2 "vendor:botan/sha2" import sha3 "vendor:botan/sha3" import shake "vendor:botan/shake" diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 508af63ad..0e347a702 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -16,16 +16,16 @@ import "core:testing" import "core:fmt" import "core:strings" -import "core:crypto/md5" -import "core:crypto/sha1" import "core:crypto/sha2" import "core:crypto/sha3" -import "core:crypto/keccak" import "core:crypto/shake" import "core:crypto/blake2b" import "core:crypto/blake2s" import "core:crypto/sm3" import "core:crypto/siphash" +import "core:crypto/legacy/keccak" +import "core:crypto/legacy/md5" +import "core:crypto/legacy/sha1" import "core:os" TEST_count := 0 diff --git a/tests/vendor/botan/test_vendor_botan.odin b/tests/vendor/botan/test_vendor_botan.odin index 661f79790..465589407 100644 --- a/tests/vendor/botan/test_vendor_botan.odin +++ b/tests/vendor/botan/test_vendor_botan.odin @@ -17,11 +17,11 @@ import "core:fmt" import "core:os" import "core:strings" -import "vendor:botan/md5" -import "vendor:botan/sha1" +import "vendor:botan/legacy/md5" +import "vendor:botan/legacy/sha1" import "vendor:botan/sha2" import "vendor:botan/sha3" -import "vendor:botan/keccak" +import "vendor:botan/legacy/keccak" import "vendor:botan/shake" import "vendor:botan/blake2b" import "vendor:botan/sm3" diff --git a/vendor/botan/README.md b/vendor/botan/README.md index 890949158..8dc4e0575 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -9,13 +9,13 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | Algorithm | | |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | -| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | -| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | -| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | | [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | | [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | | [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | +| legacy/[Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | +| legacy/[MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | +| legacy/[SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | #### High level API Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`. diff --git a/vendor/botan/legacy/README.md b/vendor/botan/legacy/README.md new file mode 100644 index 000000000..e1ba6f54b --- /dev/null +++ b/vendor/botan/legacy/README.md @@ -0,0 +1,10 @@ +# crypto/legacy + +These are algorithms that are shipped solely for the purpose of +interoperability with legacy systems. The use of these packages in +any other capacity is discouraged, especially those that are known +to be broken. + +- keccak - The draft version of the algorithm that became SHA-3 +- MD5 - Broken (https://eprint.iacr.org/2005/075) +- SHA-1 - Broken (https://eprint.iacr.org/2017/190) diff --git a/vendor/botan/keccak/keccak.odin b/vendor/botan/legacy/keccak/keccak.odin similarity index 99% rename from vendor/botan/keccak/keccak.odin rename to vendor/botan/legacy/keccak/keccak.odin index 1d08f427d..02f05378c 100644 --- a/vendor/botan/keccak/keccak.odin +++ b/vendor/botan/legacy/keccak/keccak.odin @@ -14,7 +14,7 @@ package vendor_keccak import "core:os" import "core:io" -import botan "../bindings" +import botan "../../bindings" /* High level API diff --git a/vendor/botan/md5/md5.odin b/vendor/botan/legacy/md5/md5.odin similarity index 98% rename from vendor/botan/md5/md5.odin rename to vendor/botan/legacy/md5/md5.odin index c2ed7c45c..7071a9234 100644 --- a/vendor/botan/md5/md5.odin +++ b/vendor/botan/legacy/md5/md5.odin @@ -14,7 +14,7 @@ package vendor_md5 import "core:os" import "core:io" -import botan "../bindings" +import botan "../../bindings" /* High level API diff --git a/vendor/botan/sha1/sha1.odin b/vendor/botan/legacy/sha1/sha1.odin similarity index 98% rename from vendor/botan/sha1/sha1.odin rename to vendor/botan/legacy/sha1/sha1.odin index 929f4c0be..0fc79d6cc 100644 --- a/vendor/botan/sha1/sha1.odin +++ b/vendor/botan/legacy/sha1/sha1.odin @@ -14,7 +14,7 @@ package vendor_sha1 import "core:os" import "core:io" -import botan "../bindings" +import botan "../../bindings" /* High level API From 9cc5cd9d406bd4dc6a1258d2d63ade6e04b05c18 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 17 Nov 2023 19:54:06 +0900 Subject: [PATCH 112/160] core/crypto: Update the documentation (NFC) --- core/crypto/README.md | 75 ++++++++++++++++++++++-------------------- vendor/botan/README.md | 42 +++++++++++++---------- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/core/crypto/README.md b/core/crypto/README.md index 35ed9ca70..adb815df4 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -1,11 +1,14 @@ # crypto -A crypto library for the Odin language + +A cryptography library for the Odin language ## Supported + This library offers various algorithms implemented in Odin. -Please see the chart below for the options. +Please see the chart below for some of the options. ## Hashing algorithms + | Algorithm | | |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | @@ -19,65 +22,65 @@ Please see the chart below for the options. | legacy/[SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | #### High level API -Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*. -Included in these groups are six procedures. -* `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally -* `hash_bytes` - Hash a given byte slice and return the computed hash -* `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally -* `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash -* `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it -* `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true) -\* On some algorithms there is another part to the name, since they might offer control about additional parameters. -For instance, `HAVAL` offers different sizes as well as three different round amounts. -Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.hash_256_3(...)`. +Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*. +Included in these groups are six procedures. +- `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally +- `hash_bytes` - Hash a given byte slice and return the computed hash +- `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally +- `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash +- `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it +- `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true) + +\* On some algorithms there is another part to the name, since they might offer control about additional parameters. +For instance, `SHA-2` offers different sizes. +Computing a 512-bit hash is therefore achieved by calling `sha2.hash_512(...)`. #### Low level API + The above mentioned procedures internally call three procedures: `init`, `update` and `final`. You may also directly call them, if you wish. #### Example + ```odin package crypto_example // Import the desired package -import "core:crypto/md4" +import "core:crypto/blake2b" main :: proc() { input := "foo" // Compute the hash, using the high level API - computed_hash := md4.hash(input) + computed_hash := blake2b.hash(input) // Variant that takes a destination buffer, instead of returning the computed hash - hash := make([]byte, md4.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash - md4.hash(input, hash[:]) + hash := make([]byte, sha2.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash + blake2b.hash(input, hash[:]) // Compute the hash, using the low level API - ctx: md4.Md4_Context - computed_hash_low: [16]byte - md4.init(&ctx) - md4.update(&ctx, transmute([]byte)input) - md4.final(&ctx, computed_hash_low[:]) + ctx: blake2b.Context + computed_hash_low: [blake2b.DIGEST_SIZE]byte + blake2b.init(&ctx) + blake2b.update(&ctx, transmute([]byte)input) + blake2b.final(&ctx, computed_hash_low[:]) } ``` For example uses of all available algorithms, please see the tests within `tests/core/crypto`. -#### Thread safety -The crypto package is not thread-safe at the moment. This may change in the future. +## Implementation considerations -### Disclaimer -The algorithms were ported out of curiosity and due to interest in the field. -We have not had any of the code verified by a third party or tested/fuzzed by any automatic means. -Wherever we were able to find official test vectors, those were used to verify the implementation. -We do not recommend using them in a production environment, without any additional testing and/or verification. +- The crypto packages are not thread-safe. +- Best-effort is make to mitigate timing side-channels on reasonable + architectures. Architectures that are known to be unreasonable include + but are not limited to i386, i486, and WebAssembly. +- Some but not all of the packages attempt to santize sensitive data, + however this is not done consistently through the library at the moment. + As Thomas Pornin puts it "In general, such memory cleansing is a fool's + quest." +- All of these packages have not received independent third party review. -### ToDo -* Ciphers (Symmetric, Asymmetric) -* MACs (Message Authentication Code) -* CSPRNGs (Cryptographically Secure PseudoRandom Number Generator) -* KDFs (Key Derivation Function) -* KEAs (Key Exchange Algorithm) +## License -### License This library is made available under the BSD-3 license. \ No newline at end of file diff --git a/vendor/botan/README.md b/vendor/botan/README.md index 8dc4e0575..63cc45620 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -1,11 +1,14 @@ # botan -A wrapper for the Botan crypto library + +A wrapper for the Botan cryptography library ## Supported This library offers full bindings for everything exposed by Botan's FFI. -Wrappers for hashing algorithms have been added to match the API within the Odin `core:crypto` library. +Wrappers for hashing algorithms have been added to match the API within +the Odin `core:crypto` library. ## Hashing algorithms + | Algorithm | | |:-------------------------------------------------------------------------------------------------------------|:-----------------| | [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | @@ -18,16 +21,18 @@ Wrappers for hashing algorithms have been added to match the API within the Odin | legacy/[SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | #### High level API -Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`. + +Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`. Included in these groups are six procedures. -* `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally -* `hash_bytes` - Hash a given byte slice and return the computed hash -* `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally -* `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash -* `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it -* `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true) +- `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally +- `hash_bytes` - Hash a given byte slice and return the computed hash +- `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally +- `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash +- `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it +- `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true) #### Low level API + The above mentioned procedures internally call three procedures: `init`, `update` and `final`. You may also directly call them, if you wish. @@ -36,28 +41,29 @@ You may also directly call them, if you wish. package crypto_example // Import the desired package -import "vendor:botan/md4" +import "vendor:botan/blake2b" main :: proc() { input := "foo" // Compute the hash, using the high level API - computed_hash := md4.hash(input) + computed_hash := blake2b.hash(input) // Variant that takes a destination buffer, instead of returning the computed hash - hash := make([]byte, md4.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash - md4.hash(input, hash[:]) + hash := make([]byte, blake2b.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash + blake2b.hash(input, hash[:]) // Compute the hash, using the low level API // @note: Botan's structs are opaque by design, they don't expose any fields - ctx: md4.Md4_Context - computed_hash_low: [16]byte - md4.init(&ctx) - md4.update(&ctx, transmute([]byte)input) - md4.final(&ctx, computed_hash_low[:]) + ctx: blake2b.Context + computed_hash_low: [blake2b.DIGEST_SIZE]byte + blake2b.init(&ctx) + blake2b.update(&ctx, transmute([]byte)input) + blake2b.final(&ctx, computed_hash_low[:]) } ``` For example uses of all available algorithms, please see the tests within `tests/vendor/botan`. ### License + This library is made available under the BSD-3 license. \ No newline at end of file From 0c97f6aa4e2c544bcaab8724f8e798e5998a31e5 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 18 Nov 2023 18:01:14 +0100 Subject: [PATCH 113/160] Fix unhandled EOF in streaming io on Windows --- core/os/file_windows.odin | 32 ++++++++++++++++---------------- core/os/stream.odin | 9 +++++---- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 9d62014af..0b0baeea3 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -149,7 +149,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { return } -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { +read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { if len(data) == 0 { return 0, ERROR_NONE } @@ -158,32 +158,32 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { m: u32 is_console := win32.GetConsoleMode(handle, &m) - - single_read_length: win32.DWORD - total_read: int length := len(data) // NOTE(Jeroen): `length` can't be casted to win32.DWORD here because it'll overflow if > 4 GiB and return 0 if exactly that. to_read := min(i64(length), MAX_RW) - e: win32.BOOL if is_console { - n, err := read_console(handle, data[total_read:][:to_read]) - total_read += n + total_read, err = read_console(handle, data[total_read:][:to_read]) if err != 0 { - return int(total_read), err + return total_read, err } } else { // NOTE(Jeroen): So we cast it here *after* we've ensured that `to_read` is at most MAX_RW (1 GiB) - e = win32.ReadFile(handle, &data[total_read], win32.DWORD(to_read), &single_read_length, nil) + bytes_read: win32.DWORD + if e := win32.ReadFile(handle, &data[total_read], win32.DWORD(to_read), &bytes_read, nil); e { + // Successful read can mean two things, including EOF, see: + // https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file + if bytes_read == 0 { + return 0, ERROR_HANDLE_EOF + } else { + return int(bytes_read), ERROR_NONE + } + } else { + return 0, Errno(win32.GetLastError()) + } } - if single_read_length <= 0 || !e { - err := Errno(win32.GetLastError()) - return int(total_read), err - } - total_read += int(single_read_length) - - return int(total_read), ERROR_NONE + return total_read, ERROR_NONE } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { diff --git a/core/os/stream.odin b/core/os/stream.odin index 2b4c83663..a09c62e2b 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -27,9 +27,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, case .Read: n_int, os_err = read(fd, p) n = i64(n_int) - if os_err != 0 { - err = .Unknown - } + case .Read_At: when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) { n_int, os_err = read_at(fd, p, offset) @@ -57,7 +55,10 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } } if err == nil && os_err != 0 { - err = .Unknown + switch os_err { + case ERROR_HANDLE_EOF: err = .EOF + case: err = .Unknown + } } return } From db89c2ccd01884845fcbf7beb9bdb7abc1ecf275 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 18 Nov 2023 18:13:56 +0100 Subject: [PATCH 114/160] Remap EOF for Windows in stream proc --- core/os/stream.odin | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/os/stream.odin b/core/os/stream.odin index a09c62e2b..a5132239f 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -55,10 +55,12 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } } if err == nil && os_err != 0 { - switch os_err { - case ERROR_HANDLE_EOF: err = .EOF - case: err = .Unknown + when ODIN_OS == .Windows { + if os_err == ERROR_HANDLE_EOF { + return n, .EOF + } } + err = .Unknown } return } From d9fab5e824b5caee48ed96cf76e0011f0cdf6742 Mon Sep 17 00:00:00 2001 From: Paco Pascal Date: Sat, 18 Nov 2023 20:56:22 -0500 Subject: [PATCH 115/160] Return value of _umtx_op on FreeBSD wasn't checked correctly --- src/threading.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/threading.cpp b/src/threading.cpp index 3ddc05b0a..74aa3eb7e 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -660,7 +660,7 @@ gb_internal void futex_broadcast(Futex *addr) { gb_internal void futex_wait(Futex *addr, Footex val) { for (;;) { int ret = _umtx_op(addr, UMTX_OP_WAIT_UINT, val, 0, NULL); - if (ret == 0) { + if (ret == -1) { if (errno == ETIMEDOUT || errno == EINTR) { continue; } From 2e64866838e6d99387bbcaf272fdeaf063b1a308 Mon Sep 17 00:00:00 2001 From: laytan Date: Mon, 20 Nov 2023 21:23:12 +0100 Subject: [PATCH 116/160] fix self_cleanup causing join to fail --- tests/core/thread/test_core_thread.odin | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin index 441b2187f..c0c7396a7 100644 --- a/tests/core/thread/test_core_thread.odin +++ b/tests/core/thread/test_core_thread.odin @@ -47,8 +47,9 @@ poly_data_test :: proc(_t: ^testing.T) { t1 := thread.create_and_start_with_poly_data(b, proc(b: [MAX]byte) { b_expect: [MAX]byte = 8 expect(poly_data_test_t, b == b_expect, "thread poly data not correct") - }, self_cleanup = true) - + }) + defer free(t1) + b1: [3]uintptr = 1 b2: [MAX / 2]byte = 3 t2 := thread.create_and_start_with_poly_data2(b1, b2, proc(b: [3]uintptr, b2: [MAX / 2]byte) { @@ -56,7 +57,8 @@ poly_data_test :: proc(_t: ^testing.T) { b2_expect: [MAX / 2]byte = 3 expect(poly_data_test_t, b == b_expect, "thread poly data not correct") expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") - }, self_cleanup = true) + }) + defer free(t2) t3 := thread.create_and_start_with_poly_data3(b1, b2, uintptr(333), proc(b: [3]uintptr, b2: [MAX / 2]byte, b3: uintptr) { b_expect: [3]uintptr = 1 @@ -65,8 +67,9 @@ poly_data_test :: proc(_t: ^testing.T) { expect(poly_data_test_t, b == b_expect, "thread poly data not correct") expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") expect(poly_data_test_t, b3 == 333, "thread poly data not correct") - }, self_cleanup = true) - + }) + defer free(t3) + t4 := thread.create_and_start_with_poly_data4(uintptr(111), b1, uintptr(333), u8(5), proc(n: uintptr, b: [3]uintptr, n2: uintptr, n4: u8) { b_expect: [3]uintptr = 1 @@ -74,7 +77,8 @@ poly_data_test :: proc(_t: ^testing.T) { expect(poly_data_test_t, b == b_expect, "thread poly data not correct") expect(poly_data_test_t, n2 == 333, "thread poly data not correct") expect(poly_data_test_t, n4 == 5, "thread poly data not correct") - }, self_cleanup = true) + }) + defer free(t4) thread.join_multiple(t1, t2, t3, t4) } From 25e92551578466548584cfa9d4a2db25de9c6248 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 21 Nov 2023 16:53:14 +0100 Subject: [PATCH 117/160] Fix `string_extension_position` --- src/string.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.cpp b/src/string.cpp index 6eac4f53b..9d7ff7b89 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -205,7 +205,7 @@ gb_internal gb_inline isize string_extension_position(String const &str) { isize dot_pos = -1; isize i = str.len; while (i --> 0) { - if (str[i] == GB_PATH_SEPARATOR) + if (str[i] == '\\' || str[i] == '/') break; if (str[i] == '.') { dot_pos = i; From f97ccca514ba25096d2879b538ca718634ebc3f0 Mon Sep 17 00:00:00 2001 From: skytrias Date: Tue, 21 Nov 2023 21:01:05 +0100 Subject: [PATCH 118/160] added ToUnicode to win32 --- core/sys/windows/user32.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index ee536e0a8..cce9b3245 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -136,6 +136,7 @@ foreign user32 { GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL --- MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT --- + ToUnicode :: proc(nVirtKey: UINT, wScanCode: UINT, lpKeyState: ^BYTE, pwszBuff: LPWSTR, cchBuff: c_int, wFlags: UINT) -> c_int --- SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- UnhookWindowsHookEx :: proc(hhk: HHOOK) -> BOOL --- From e2e18324ed3b391d5f2697471351028eb3eb46f5 Mon Sep 17 00:00:00 2001 From: reavencode Date: Tue, 21 Nov 2023 22:44:46 +0100 Subject: [PATCH 119/160] Add DwmGetWindowAttribute to core/sys/windows --- core/sys/windows/dwmapi.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/sys/windows/dwmapi.odin b/core/sys/windows/dwmapi.odin index 9b5916ab1..34616fb98 100644 --- a/core/sys/windows/dwmapi.odin +++ b/core/sys/windows/dwmapi.odin @@ -43,5 +43,6 @@ foreign dwmapi { DwmFlush :: proc() -> HRESULT --- DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT --- DwmExtendFrameIntoClientArea :: proc(hWnd: HWND, pMarInset: PMARGINS) -> HRESULT --- + DwmGetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: PVOID, cbAttribute: DWORD) -> HRESULT --- DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT --- } From 3e7b5670fbb8d56b428375140586c5c94f2c8814 Mon Sep 17 00:00:00 2001 From: evertonse Date: Tue, 21 Nov 2023 18:48:47 -0300 Subject: [PATCH 120/160] Check for llvm-config14 on unix --- build_odin.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build_odin.sh b/build_odin.sh index 2a2505c97..f9747b52c 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -27,11 +27,13 @@ error() { if [ -z "$LLVM_CONFIG" ]; then # darwin, linux, openbsd if [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17" + elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14" elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13" elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12" elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11" # freebsd elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config-17" + elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config-14" elif [ -n "$(command -v llvm-config13)" ]; then LLVM_CONFIG="llvm-config-13" elif [ -n "$(command -v llvm-config12)" ]; then LLVM_CONFIG="llvm-config-12" elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11" From 63b6e8216c0f234a8ade90b6e6a2f1ad95e42e2e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 22 Nov 2023 02:57:43 +0100 Subject: [PATCH 121/160] Fix errant tab in alignment. --- core/log/log.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/log/log.odin b/core/log/log.odin index f3554791b..021a46000 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -60,9 +60,9 @@ Logger_Proc :: runtime.Logger_Proc /* Logger :: struct { procedure: Logger_Proc, - data: rawptr, + data: rawptr, lowest_level: Level, - options: Logger_Options, + options: Logger_Options, } */ Logger :: runtime.Logger From 6749639eb133dad03a87aad55feb82f0a3be2e29 Mon Sep 17 00:00:00 2001 From: Brennen Shaughnessy Date: Tue, 14 Nov 2023 09:12:23 -0500 Subject: [PATCH 122/160] Add various missing windows procedures --- core/sys/windows/gdi32.odin | 7 +++++++ core/sys/windows/kernel32.odin | 13 ++++++++++++- core/sys/windows/types.odin | 10 ++++++++++ core/sys/windows/user32.odin | 3 +++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 9e2294c71..801e483e7 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -10,6 +10,8 @@ foreign gdi32 { DeleteObject :: proc(ho: HGDIOBJ) -> BOOL --- SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- + CreateCompatibleDC :: proc(hdc: HDC) -> HDC --- + CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- CreateDIBitmap :: proc( @@ -81,6 +83,11 @@ foreign gdi32 { GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL --- CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH --- + + GetObjectW :: proc(h: HANDLE, c: c_int, pv: LPVOID) -> int --- + CreateCompatibleBitmap :: proc(hdc: HDC, cx, cy: c_int) -> HBITMAP --- + BitBlt :: proc(hdc: HDC, x, y, cx, cy: c_int, hdcSrc: HDC, x1, y1: c_int, rop: DWORD) -> BOOL --- + GetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start, cLines: UINT, lpvBits: LPVOID, lpbmi: ^BITMAPINFO, usage: UINT) -> int --- } RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF { diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 0c612a974..016cb0bf8 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -290,6 +290,14 @@ foreign kernel32 { hTemplateFile: HANDLE, ) -> HANDLE --- + GetFileTime :: proc( + hFile: HANDLE, + lpCreationTime: LPFILETIME, + lpLastAccessTime: LPFILETIME, + lpLastWriteTime: LPFILETIME, + ) -> BOOL --- + CompareFileTime :: proc(lpFileTime1: LPFILETIME, lpFileTime2: LPFILETIME) -> LONG --- + FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE --- FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL --- FindClose :: proc(findFile: HANDLE) -> BOOL --- @@ -346,6 +354,9 @@ foreign kernel32 { LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- LocalFree :: proc(mem: LPVOID) -> LPVOID --- + GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID --- + GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- + GlobalFree :: proc(mem: LPVOID) -> LPVOID --- ReadDirectoryChangesW :: proc( hDirectory: HANDLE, @@ -414,7 +425,7 @@ foreign kernel32 { GetConsoleWindow :: proc() -> HWND --- GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL --- SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL --- - SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute : BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL --- + SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL --- GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index d5377eb2f..dcd3ad672 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -1969,6 +1969,16 @@ BITMAPINFO :: struct { bmiColors: [1]RGBQUAD, } +BITMAP :: struct { + bmType: LONG, + bmWidth: LONG, + bmHeight: LONG, + bmWidthBytes: LONG, + bmPlanes: WORD, + bmBitsPixel: WORD, + bmBits: LPVOID, +} + // pixel types PFD_TYPE_RGBA :: 0 PFD_TYPE_COLORINDEX :: 1 diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index ee536e0a8..4fe29d2f8 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -160,6 +160,8 @@ foreign user32 { MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR --- MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR --- EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL --- + + EnumWindows :: proc(lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL --- SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT --- GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT --- @@ -310,6 +312,7 @@ Monitor_From_Flags :: enum DWORD { } Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL +Window_Enum_Proc :: #type proc "stdcall" (HWND, LPARAM) -> BOOL USER_DEFAULT_SCREEN_DPI :: 96 DPI_AWARENESS_CONTEXT :: distinct HANDLE From 4af77aeff684cf9a4a764a9e18d942f232cd7caf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 Nov 2023 15:04:41 +0000 Subject: [PATCH 123/160] Lower `MAP_MIN_LOG2_CAPACITY` from `6` to `3` (64->8) --- core/runtime/dynamic_map_internal.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index bdf0979cb..491a7974d 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -44,7 +44,7 @@ _ :: intrinsics MAP_LOAD_FACTOR :: 75 // Minimum log2 capacity. -MAP_MIN_LOG2_CAPACITY :: 6 // 64 elements +MAP_MIN_LOG2_CAPACITY :: 3 // 8 elements // Has to be less than 100% though. #assert(MAP_LOAD_FACTOR < 100) From 08d032859f4b3fe61785414ca97981b1e1c8c036 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 22 Nov 2023 16:16:43 +0100 Subject: [PATCH 124/160] use start pos as end pos if end node is nil --- core/odin/ast/clone.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index c9bfdfe89..a419369b8 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -24,7 +24,7 @@ new_from_positions :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { } new_from_pos_and_end_node :: proc($T: typeid, pos: tokenizer.Pos, end: ^Node) -> ^T { - return new(T, pos, end != nil ? end.end : {}) + return new(T, pos, end != nil ? end.end : pos) } new :: proc { From a0e6ae6f335016ea07958cdb665edcb499c22e8f Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 22 Nov 2023 17:15:27 +0100 Subject: [PATCH 125/160] return uintptr from type_union_tag_offset --- core/intrinsics/intrinsics.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index afa0efa36..c23cbd473 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -165,7 +165,7 @@ type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- type_union_tag_type :: proc($T: typeid) -> typeid where type_is_union(T) --- -type_union_tag_offset :: proc($T: typeid) -> int where type_is_union(T) --- +type_union_tag_offset :: proc($T: typeid) -> uintptr where type_is_union(T) --- type_union_base_tag_value :: proc($T: typeid) -> int where type_is_union(U) --- type_union_variant_count :: proc($T: typeid) -> int where type_is_union(T) --- type_variant_type_of :: proc($T: typeid, $index: int) -> typeid where type_is_union(T) --- From 29f1b79d70a68c4702870da0a891bb1209519dad Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Wed, 22 Nov 2023 23:56:58 +0100 Subject: [PATCH 126/160] Add setup_once and clear_all, tidy up old code and add a few comments --- core/text/edit/text_edit.odin | 106 ++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin index 8520ba674..8979088a7 100644 --- a/core/text/edit/text_edit.odin +++ b/core/text/edit/text_edit.odin @@ -1,4 +1,4 @@ -package text_edit +package edit /* Based off the articles by rxi: @@ -63,7 +63,9 @@ Translation :: enum u32 { Soft_Line_End, } - +// init the state to some timeout and set the respective allocators +// - undo_state_allocator dictates the dynamic undo|redo arrays allocators +// - undo_text_allocator is the allocator which allocates strings only init :: proc(s: ^State, undo_text_allocator, undo_state_allocator: runtime.Allocator, undo_timeout := DEFAULT_UNDO_TIMEOUT) { s.undo_timeout = undo_timeout @@ -74,6 +76,7 @@ init :: proc(s: ^State, undo_text_allocator, undo_state_allocator: runtime.Alloc s.redo.allocator = undo_state_allocator } +// clear undo|redo strings and delete their stacks destroy :: proc(s: ^State) { undo_clear(s, &s.undo) undo_clear(s, &s.redo) @@ -82,7 +85,6 @@ destroy :: proc(s: ^State) { s.builder = nil } - // Call at the beginning of each frame begin :: proc(s: ^State, id: u64, builder: ^strings.Builder) { assert(builder != nil) @@ -92,11 +94,7 @@ begin :: proc(s: ^State, id: u64, builder: ^strings.Builder) { s.id = id s.selection = {len(builder.buf), 0} s.builder = builder - s.current_time = time.tick_now() - if s.undo_timeout <= 0 { - s.undo_timeout = DEFAULT_UNDO_TIMEOUT - } - set_text(s, string(s.builder.buf[:])) + update_time(s) undo_clear(s, &s.undo) undo_clear(s, &s.redo) } @@ -107,12 +105,37 @@ end :: proc(s: ^State) { s.builder = nil } -set_text :: proc(s: ^State, text: string) { - strings.builder_reset(s.builder) - strings.write_string(s.builder, text) +// update current time so "insert" can check for timeouts +update_time :: proc(s: ^State) { + s.current_time = time.tick_now() + if s.undo_timeout <= 0 { + s.undo_timeout = DEFAULT_UNDO_TIMEOUT + } } +// setup the builder, selection and undo|redo state once allowing to retain selection +setup_once :: proc(s: ^State, builder: ^strings.Builder) { + s.builder = builder + s.selection = { len(builder.buf), 0 } + undo_clear(s, &s.undo) + undo_clear(s, &s.redo) +} +// returns true when the builder had content to be cleared +// clear builder&selection and the undo|redo stacks +clear_all :: proc(s: ^State) -> (cleared: bool) { + if len(s.builder.buf) > 0 { + clear(&s.builder.buf) + s.selection = {} + cleared = true + } + + undo_clear(s, &s.undo) + undo_clear(s, &s.redo) + return +} + +// push current text state to the wanted undo|redo stack undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error { text := string(s.builder.buf[:]) item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator) or_return) @@ -125,18 +148,21 @@ undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator return nil } +// pop undo|redo state - push to redo|undo - set selection & text undo :: proc(s: ^State, undo, redo: ^[dynamic]^Undo_State) { if len(undo) > 0 { undo_state_push(s, redo) item := pop(undo) s.selection = item.selection #no_bounds_check { - set_text(s, string(item.text[:item.len])) + strings.builder_reset(s.builder) + strings.write_string(s.builder, string(item.text[:item.len])) } free(item, s.undo_text_allocator) } } +// iteratively clearn the undo|redo stack and free each allocated text state undo_clear :: proc(s: ^State, undo: ^[dynamic]^Undo_State) { for len(undo) > 0 { item := pop(undo) @@ -144,6 +170,7 @@ undo_clear :: proc(s: ^State, undo: ^[dynamic]^Undo_State) { } } +// clear redo stack and check if the undo timeout gets hit undo_check :: proc(s: ^State) { undo_clear(s, &s.redo) if time.tick_diff(s.last_edit_time, s.current_time) > s.undo_timeout { @@ -152,8 +179,7 @@ undo_check :: proc(s: ^State) { s.last_edit_time = s.current_time } - - +// insert text into the edit state - deletes the current selection input_text :: proc(s: ^State, text: string) { if len(text) == 0 { return @@ -166,6 +192,7 @@ input_text :: proc(s: ^State, text: string) { s.selection = {offset, offset} } +// insert slice of runes into the edit state - deletes the current selection input_runes :: proc(s: ^State, text: []rune) { if len(text) == 0 { return @@ -182,43 +209,55 @@ input_runes :: proc(s: ^State, text: []rune) { s.selection = {offset, offset} } +// insert a single rune into the edit state - deletes the current selection +input_rune :: proc(s: ^State, r: rune) { + if has_selection(s) { + selection_delete(s) + } + offset := s.selection[0] + b, w := utf8.encode_rune(r) + insert(s, offset, string(b[:w])) + offset += w + s.selection = {offset, offset} +} +// insert a single rune into the edit state - deletes the current selection insert :: proc(s: ^State, at: int, text: string) { undo_check(s) inject_at(&s.builder.buf, at, text) } +// remove the wanted range withing, usually the selection within byte indices remove :: proc(s: ^State, lo, hi: int) { undo_check(s) remove_range(&s.builder.buf, lo, hi) } - - +// true if selection head and tail dont match and form a selection of multiple characters has_selection :: proc(s: ^State) -> bool { return s.selection[0] != s.selection[1] } +// return the clamped lo/hi of the current selection +// since the selection[0] moves around and could be ahead of selection[1] +// useful when rendering and needing left->right sorted_selection :: proc(s: ^State) -> (lo, hi: int) { lo = min(s.selection[0], s.selection[1]) hi = max(s.selection[0], s.selection[1]) lo = clamp(lo, 0, len(s.builder.buf)) hi = clamp(hi, 0, len(s.builder.buf)) - s.selection[0] = lo - s.selection[1] = hi return } - +// delete the current selection range and set the proper selection afterwards selection_delete :: proc(s: ^State) { lo, hi := sorted_selection(s) remove(s, lo, hi) s.selection = {lo, lo} } - - -translate_position :: proc(s: ^State, pos: int, t: Translation) -> int { +// translates the caret position +translate_position :: proc(s: ^State, t: Translation) -> int { is_continuation_byte :: proc(b: byte) -> bool { return b >= 0x80 && b < 0xc0 } @@ -227,9 +266,7 @@ translate_position :: proc(s: ^State, pos: int, t: Translation) -> int { } buf := s.builder.buf[:] - - pos := pos - pos = clamp(pos, 0, len(buf)) + pos := clamp(s.selection[0], 0, len(buf)) switch t { case .Start: @@ -280,6 +317,7 @@ translate_position :: proc(s: ^State, pos: int, t: Translation) -> int { return clamp(pos, 0, len(buf)) } +// Moves the position of the caret (both sides of the selection) move_to :: proc(s: ^State, t: Translation) { if t == .Left && has_selection(s) { lo, _ := sorted_selection(s) @@ -288,32 +326,36 @@ move_to :: proc(s: ^State, t: Translation) { _, hi := sorted_selection(s) s.selection = {hi, hi} } else { - pos := translate_position(s, s.selection[0], t) + pos := translate_position(s, t) s.selection = {pos, pos} } } + +// Moves only the head of the selection and leaves the tail uneffected select_to :: proc(s: ^State, t: Translation) { - s.selection[0] = translate_position(s, s.selection[0], t) + s.selection[0] = translate_position(s, t) } + +// Deletes everything between the caret and resultant position delete_to :: proc(s: ^State, t: Translation) { if has_selection(s) { selection_delete(s) } else { lo := s.selection[0] - hi := translate_position(s, lo, t) + hi := translate_position(s, t) lo, hi = min(lo, hi), max(lo, hi) remove(s, lo, hi) s.selection = {lo, lo} } } - +// return the currently selected text current_selected_text :: proc(s: ^State) -> string { lo, hi := sorted_selection(s) return string(s.builder.buf[lo:hi]) } - +// copy & delete the current selection when copy() succeeds cut :: proc(s: ^State) -> bool { if copy(s) { selection_delete(s) @@ -322,6 +364,8 @@ cut :: proc(s: ^State) -> bool { return false } +// try and copy the currently selected text to the clipboard +// State.set_clipboard needs to be assigned copy :: proc(s: ^State) -> bool { if s.set_clipboard != nil { return s.set_clipboard(s.clipboard_user_data, current_selected_text(s)) @@ -329,6 +373,8 @@ copy :: proc(s: ^State) -> bool { return s.set_clipboard != nil } +// reinsert whatever the get_clipboard would return +// State.get_clipboard needs to be assigned paste :: proc(s: ^State) -> bool { if s.get_clipboard != nil { input_text(s, s.get_clipboard(s.clipboard_user_data) or_return) From f635d3d8afec548178fb67562963cc9553b85685 Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Thu, 23 Nov 2023 00:02:48 +0100 Subject: [PATCH 127/160] forgot to use the old package name --- core/text/edit/text_edit.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin index 8979088a7..98477a637 100644 --- a/core/text/edit/text_edit.odin +++ b/core/text/edit/text_edit.odin @@ -1,4 +1,4 @@ -package edit +package text_edit /* Based off the articles by rxi: From 3d90e580c596eddb07108e4a417412bcd4910b8c Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Thu, 23 Nov 2023 00:04:06 +0100 Subject: [PATCH 128/160] check to see if s.builder is nil --- core/text/edit/text_edit.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin index 98477a637..3f6565557 100644 --- a/core/text/edit/text_edit.odin +++ b/core/text/edit/text_edit.odin @@ -124,7 +124,7 @@ setup_once :: proc(s: ^State, builder: ^strings.Builder) { // returns true when the builder had content to be cleared // clear builder&selection and the undo|redo stacks clear_all :: proc(s: ^State) -> (cleared: bool) { - if len(s.builder.buf) > 0 { + if s.builder != nil && len(s.builder.buf) > 0 { clear(&s.builder.buf) s.selection = {} cleared = true From 3baf8d92c3efc71d09e28de97a0ba7f303e349e6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 01:20:19 +0000 Subject: [PATCH 129/160] Add assert to disallow `-no-crt` when importing `core:c/libc` --- core/c/libc/types.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/c/libc/types.odin b/core/c/libc/types.odin index a49e52fb6..cc844c1c5 100644 --- a/core/c/libc/types.odin +++ b/core/c/libc/types.odin @@ -2,6 +2,8 @@ package libc import "core:c" +#assert(!ODIN_NO_CRT, `"core:c/libc" cannot be imported when '-no-crt' is used`) + char :: c.char // assuming -funsigned-char schar :: c.schar From 4c1a9d2b3f821733ac79135c76e13d3be6f3ed4f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 16:56:18 +0000 Subject: [PATCH 130/160] Fix `&x[i]` of `^#soa` types --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5a8b57df6..7b90677c8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2339,7 +2339,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * ast_node(ue, UnaryExpr, node); if (ast_node_expect(ue->expr, Ast_IndexExpr)) { ast_node(ie, IndexExpr, ue->expr); - Type *soa_type = type_of_expr(ie->expr); + Type *soa_type = type_deref(type_of_expr(ie->expr)); GB_ASSERT(is_type_soa_struct(soa_type)); o->type = alloc_type_soa_pointer(soa_type); } else { @@ -7428,7 +7428,7 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count = t->Struct.soa_count; } o->type = t->Struct.soa_elem; - if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable) { + if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable || indirection) { o->mode = Addressing_SoaVariable; } else { o->mode = Addressing_Value; From 0888c69b57604b674b6c220c6f60297d98bae58c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 17:16:21 +0000 Subject: [PATCH 131/160] Remove unneeded `typeid_of` --- core/runtime/core_builtin_soa.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/runtime/core_builtin_soa.odin b/core/runtime/core_builtin_soa.odin index f3882a9a8..6313a28f5 100644 --- a/core/runtime/core_builtin_soa.odin +++ b/core/runtime/core_builtin_soa.odin @@ -287,7 +287,7 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat footer := raw_soa_footer(array) if size_of(E) > 0 && cap(array)-len(array) > 0 { - ti := type_info_of(typeid_of(T)) + ti := type_info_of(T) ti = type_info_base(ti) si := &ti.variant.(Type_Info_Struct) field_count: uintptr From f809788f75f997ceebbbbfa0aa138f2ae2011e1e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 17:31:00 +0000 Subject: [PATCH 132/160] Add missing type information for soa structs --- src/check_builtin.cpp | 2 ++ src/checker.cpp | 5 +++++ src/llvm_backend_expr.cpp | 6 ++++++ src/llvm_backend_type.cpp | 7 ++++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ce628bc1d..c0061a397 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2088,6 +2088,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As t = default_type(t); add_type_info_type(c, t); + GB_ASSERT(t_type_info_ptr != nullptr); + add_type_info_type(c, t_type_info_ptr); if (is_operand_value(o) && is_type_typeid(t)) { add_package_dependency(c, "runtime", "__type_info_of"); diff --git a/src/checker.cpp b/src/checker.cpp index 0366cf05d..6dae99027 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2211,9 +2211,14 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { Entity *e = entry.value; switch (bt->Struct.soa_kind) { case StructSoa_Dynamic: + add_min_dep_type_info(c, t_type_info_ptr); // append_soa + add_min_dep_type_info(c, t_allocator); /*fallthrough*/ case StructSoa_Slice: + add_min_dep_type_info(c, t_int); + add_min_dep_type_info(c, t_uint); + /*fallthrough*/ case StructSoa_Fixed: add_min_dep_type_info(c, alloc_type_pointer(e->type)); break; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 8678a125c..d1176f896 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2939,6 +2939,12 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { } else if (is_type_soa_pointer(tv.type)) { ast_node(ie, IndexExpr, ue_expr); lbValue addr = lb_build_addr_ptr(p, ie->expr); + + if (is_type_pointer(type_deref(addr.type))) { + addr = lb_emit_load(p, addr); + } + GB_ASSERT(is_type_pointer(addr.type)); + lbValue index = lb_build_expr(p, ie->index); if (!build_context.no_bounds_check) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 02dad2a3a..e291e40a5 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -9,7 +9,12 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ } } if (err_on_not_found) { - GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); + gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count); + for (auto const &entry : *set) { + isize type_info_index = entry.key; + gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index])); + } + GB_PANIC("NOT FOUND"); } return -1; } From e78ee90ac229468e88281fece02b752cc8160744 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:58:26 +0100 Subject: [PATCH 133/160] Remove code that skipped checking blank params --- src/check_expr.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7b90677c8..71accfb81 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5606,9 +5606,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A for (isize i = 0; i < pt->param_count; i++) { if (!visited[i]) { Entity *e = pt->params->Tuple.variables[i]; - if (is_blank_ident(e->token)) { - continue; - } if (e->kind == Entity_Variable) { if (e->Variable.param_value.kind != ParameterValue_Invalid) { ordered_operands[i].mode = Addressing_Value; From 3102abf1aabdfff798cc0d2020c07c7138b59648 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 24 Nov 2023 10:57:18 +0000 Subject: [PATCH 134/160] mem zero rather than store to a union where the variant is of size zero --- src/llvm_backend.hpp | 1 + src/llvm_backend_general.cpp | 12 +++++++++--- src/llvm_backend_utility.cpp | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 5894dd38a..3e4070367 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -550,6 +550,7 @@ gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLV gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile); +gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile); gb_internal gb_inline i64 lb_max_zero_init_size(void) { return cast(i64)(4*build_context.int_size); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index fdcf94f29..c149ec853 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1332,6 +1332,8 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV Type *pt = base_type(type_deref(parent.type)); GB_ASSERT(pt->kind == Type_Union); if (pt->Union.kind == UnionType_shared_nil) { + GB_ASSERT(type_size_of(variant_type)); + lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil"); lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil"); lbBlock *done = lb_create_block(p, "shared_nil.done"); @@ -1353,9 +1355,13 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV } else { - lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); - - lb_emit_store(p, underlying, variant); + if (type_size_of(variant_type) == 0) { + unsigned alignment = 1; + lb_mem_zero_ptr_internal(p, parent.value, pt->Union.variant_block_size, alignment, false); + } else { + lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); + lb_emit_store(p, underlying, variant); + } lb_emit_store_union_variant_tag(p, parent, variant_type); } } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index d8dbfd736..be3ae9c8a 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -57,6 +57,10 @@ gb_internal lbValue lb_correct_endianness(lbProcedure *p, lbValue value) { return value; } +gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile) { + return lb_mem_zero_ptr_internal(p, ptr, LLVMConstInt(lb_type(p->module, t_uint), len, false), alignment, is_volatile); +} + gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) { bool is_inlinable = false; From c12eb3ec933b2415b5d6ca12e173b1fac8c3c847 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 24 Nov 2023 11:44:20 +0000 Subject: [PATCH 135/160] Improve returning a struct directly for certain ABIs; reuse the temp callee return struct memory when needed --- src/llvm_backend.hpp | 2 ++ src/llvm_backend_stmt.cpp | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 3e4070367..4e193bcea 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -339,6 +339,8 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + LLVMValueRef temp_callee_return_struct_memory; + Ast *curr_stmt; Array scope_stack; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9d688be6a..002fef881 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1846,9 +1846,25 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { LLVMBuildRetVoid(p->builder); } else { LLVMValueRef ret_val = res.value; - ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type); - if (p->abi_function_type->ret.cast_type != nullptr) { - ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type); + LLVMTypeRef ret_type = p->abi_function_type->ret.type; + if (LLVMTypeRef cast_type = p->abi_function_type->ret.cast_type) { + ret_type = cast_type; + } + + if (LLVMGetTypeKind(ret_type) == LLVMStructTypeKind) { + LLVMTypeRef src_type = LLVMTypeOf(ret_val); + + if (p->temp_callee_return_struct_memory == nullptr) { + i64 max_align = gb_max(lb_alignof(ret_type), lb_alignof(src_type)); + p->temp_callee_return_struct_memory = llvm_alloca(p, ret_type, max_align); + } + // reuse the temp return value memory where possible + LLVMValueRef ptr = p->temp_callee_return_struct_memory; + LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); + LLVMBuildStore(p->builder, ret_val, nptr); + ret_val = LLVMBuildLoad2(p->builder, ret_type, ptr, ""); + } else { + ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type); } lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); From 8063569cdd6277044a3eb6d5ae7aee63f519cb85 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Fri, 24 Nov 2023 23:27:12 +1100 Subject: [PATCH 136/160] [net]: Add send_any, recv_any variants to proc groups for Any_Socket --- core/net/socket.odin | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/core/net/socket.odin b/core/net/socket.odin index 40fa6ab56..1bfa52257 100644 --- a/core/net/socket.odin +++ b/core/net/socket.odin @@ -148,7 +148,29 @@ recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_en return _recv_udp(socket, buf) } -recv :: proc{recv_tcp, recv_udp} +/* + Receive data from into a buffer from any socket. + + Note: `remote_endpoint` parameter is non-nil only if the socket type is UDP. On TCP sockets it + will always return `nil`. +*/ +recv_any :: proc(socket: Any_Socket, buf: []byte) -> ( + bytes_read: int, + remote_endpoint: Maybe(Endpoint), + err: Network_Error, +) { + switch socktype in socket { + case TCP_Socket: + bytes_read, err := recv_tcp(socktype, buf) + return bytes_read, nil, err + case UDP_Socket: + bytes_read, endpoint, err := recv_udp(socktype, buf) + return bytes_read, endpoint, err + case: panic("Not supported") + } +} + +recv :: proc{recv_tcp, recv_udp, recv_any} /* Repeatedly sends data until the entire buffer is sent. @@ -168,7 +190,20 @@ send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_writte return _send_udp(socket, buf, to) } -send :: proc{send_tcp, send_udp} +send_any :: proc(socket: Any_Socket, buf: []byte, to: Maybe(Endpoint) = nil) -> ( + bytes_written: int, + err: Network_Error, +) { + switch socktype in socket { + case TCP_Socket: + return send_tcp(socktype, buf) + case UDP_Socket: + return send_udp(socktype, buf, to.(Endpoint)) + case: panic("Not supported") + } +} + +send :: proc{send_tcp, send_udp, send_any} shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { return _shutdown(socket, manner) @@ -180,4 +215,4 @@ set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { return _set_blocking(socket, should_block) -} \ No newline at end of file +} From ff0e976ff3dc1f4a783f1e9d93b18f4a1ce34f25 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Fri, 24 Nov 2023 23:57:53 +1100 Subject: [PATCH 137/160] [net]: Fix passing the wrong socket to on linux --- core/net/socket_linux.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index 6d3f111d1..ba48959fb 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -125,7 +125,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (An } @(private) -_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (tcp_sock: TCP_Socket, err: Network_Error) { +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (TCP_Socket, Network_Error) { errno: linux.Errno if endpoint.port == 0 { return 0, .Port_Required From 914950592cd05445d5f9b42fb6cf459a002f21fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tar=C4=B1k=20B?= Date: Fri, 24 Nov 2023 14:56:55 +0100 Subject: [PATCH 138/160] Fix indentation --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b8abe94f4..ccacf168a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1945,9 +1945,9 @@ gb_internal void print_show_help(String const arg0, String const &command) { if (run_or_build) { print_usage_line(1, "-sanitize:"); - print_usage_line(1, "Enables sanitization analysis"); - print_usage_line(1, "Options are 'address', 'memory', and 'thread'"); - print_usage_line(1, "NOTE: This flag can be used multiple times"); + print_usage_line(2, "Enables sanitization analysis"); + print_usage_line(2, "Options are 'address', 'memory', and 'thread'"); + print_usage_line(2, "NOTE: This flag can be used multiple times"); print_usage_line(0, ""); } From 70525a12cadcfa45ea78522c8003227d27f4847b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tar=C4=B1k=20B?= Date: Fri, 24 Nov 2023 20:42:11 +0100 Subject: [PATCH 139/160] Fix typo --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index ccacf168a..066a86fb8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1938,7 +1938,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-foreign-error-procedures"); - print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit"); + print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit"); print_usage_line(0, ""); } From 6f65ed6cc81318aa22b8aa6709a5eb22ecf8226b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tar=C4=B1k=20B?= Date: Fri, 24 Nov 2023 21:49:23 +0100 Subject: [PATCH 140/160] Add period at the end of sentences. --- src/main.cpp | 208 +++++++++++++++++++++++++-------------------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 066a86fb8..ab1fdda91 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -199,19 +199,19 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) { } gb_internal void usage(String argv0) { - print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0)); + print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(argv0)); print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(0, "Commands:"); print_usage_line(1, "build compile directory of .odin files, as an executable."); print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); - print_usage_line(1, "check parse, and type check a directory of .odin files"); - print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program"); - print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package"); - print_usage_line(1, "doc generate documentation on a directory of .odin files"); - print_usage_line(1, "version print version"); - print_usage_line(1, "report print information useful to reporting a bug"); + print_usage_line(1, "check parse, and type check a directory of .odin files."); + print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program."); + print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package."); + print_usage_line(1, "doc generate documentation on a directory of .odin files."); + print_usage_line(1, "version print version."); + print_usage_line(1, "report print information useful to reporting a bug."); print_usage_line(0, ""); print_usage_line(0, "For further details on a command, invoke command help:"); print_usage_line(1, "e.g. `odin build -help` or `odin help build`"); @@ -1580,7 +1580,7 @@ gb_internal void remove_temp_files(lbGenerator *gen) { gb_internal void print_show_help(String const arg0, String const &command) { - print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0)); + print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0)); print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command)); print_usage_line(0, ""); @@ -1590,35 +1590,35 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "One must contain the program's entry point, all must be in the same package."); print_usage_line(2, "Use `-file` to build a single file instead."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin build . # Build package in current directory"); - print_usage_line(3, "odin build

# Build package in "); + print_usage_line(3, "odin build . # Build package in current directory."); + print_usage_line(3, "odin build # Build package in ."); print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point."); } else if (command == "run") { print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable."); print_usage_line(2, "Append an empty flag and then the args, '-- ', to specify args for the output."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin run . # Build and run package in current directory"); - print_usage_line(3, "odin run # Build and run package in "); + print_usage_line(3, "odin run . # Build and run package in current directory."); + print_usage_line(3, "odin run # Build and run package in ."); print_usage_line(3, "odin run filename.odin -file # Build and run single-file package, must contain entry point."); } else if (command == "check") { - print_usage_line(1, "check Parse and type check directory of .odin files"); + print_usage_line(1, "check Parse and type check directory of .odin files."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin check . # Type check package in current directory"); - print_usage_line(3, "odin check # Type check package in "); + print_usage_line(3, "odin check . # Type check package in current directory."); + print_usage_line(3, "odin check # Type check package in ."); print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point."); } else if (command == "test") { - print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package"); + print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package."); } else if (command == "doc") { - print_usage_line(1, "doc generate documentation from a directory of .odin files"); + print_usage_line(1, "doc generate documentation from a directory of .odin files."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin doc . # Generate documentation on package in current directory"); - print_usage_line(3, "odin doc # Generate documentation on package in "); + print_usage_line(3, "odin doc . # Generate documentation on package in current directory."); + print_usage_line(3, "odin doc # Generate documentation on package in ."); print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package."); } else if (command == "version") { print_usage_line(1, "version print version"); } else if (command == "strip-semicolon") { print_usage_line(1, "strip-semicolon"); - print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project"); + print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project."); } bool doc = command == "doc"; @@ -1642,96 +1642,96 @@ gb_internal void print_show_help(String const arg0, String const &command) { if (doc) { print_usage_line(1, "-short"); - print_usage_line(2, "Show shortened documentation for the packages"); + print_usage_line(2, "Show shortened documentation for the packages."); print_usage_line(0, ""); print_usage_line(1, "-all-packages"); - print_usage_line(2, "Generates documentation for all packages used in the current project"); + print_usage_line(2, "Generates documentation for all packages used in the current project."); print_usage_line(0, ""); print_usage_line(1, "-doc-format"); - print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)"); + print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-out:"); - print_usage_line(2, "Set the file name of the outputted executable"); + print_usage_line(2, "Set the file name of the outputted executable."); print_usage_line(2, "Example: -out:foo.exe"); print_usage_line(0, ""); print_usage_line(1, "-o:"); - print_usage_line(2, "Set the optimization mode for compilation"); + print_usage_line(2, "Set the optimization mode for compilation."); if (LB_USE_NEW_PASS_SYSTEM) { print_usage_line(2, "Accepted values: none, minimal, size, speed, aggressive"); } else { print_usage_line(2, "Accepted values: none, minimal, size, speed"); } print_usage_line(2, "Example: -o:speed"); - print_usage_line(2, "The default is -o:minimal"); + print_usage_line(2, "The default is -o:minimal."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-show-timings"); - print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds"); + print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds."); print_usage_line(0, ""); print_usage_line(1, "-show-more-timings"); - print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds"); + print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds."); print_usage_line(0, ""); print_usage_line(1, "-show-system-calls"); - print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler"); + print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler."); print_usage_line(0, ""); print_usage_line(1, "-export-timings:"); - print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`"); + print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-export-timings:json Export compile time stats to JSON"); - print_usage_line(3, "-export-timings:csv Export compile time stats to CSV"); + print_usage_line(3, "-export-timings:json Export compile time stats to JSON."); + print_usage_line(3, "-export-timings:csv Export compile time stats to CSV."); print_usage_line(0, ""); print_usage_line(1, "-export-timings-file:"); - print_usage_line(2, "Specify the filename for `-export-timings`"); + print_usage_line(2, "Specify the filename for `-export-timings`."); print_usage_line(2, "Example: -export-timings-file:timings.json"); print_usage_line(0, ""); print_usage_line(1, "-thread-count:"); - print_usage_line(2, "Override the number of threads the compiler will use to compile with"); + print_usage_line(2, "Override the number of threads the compiler will use to compile with."); print_usage_line(2, "Example: -thread-count:2"); print_usage_line(0, ""); } if (check_only) { print_usage_line(1, "-show-unused"); - print_usage_line(2, "Shows unused package declarations within the current project"); + print_usage_line(2, "Shows unused package declarations within the current project."); print_usage_line(0, ""); print_usage_line(1, "-show-unused-with-location"); - print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location"); + print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-keep-temp-files"); - print_usage_line(2, "Keeps the temporary files generated during compilation"); + print_usage_line(2, "Keeps the temporary files generated during compilation."); print_usage_line(0, ""); } else if (strip_semicolon) { print_usage_line(1, "-keep-temp-files"); - print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files"); + print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-collection:="); - print_usage_line(2, "Defines a library collection used for imports"); + print_usage_line(2, "Defines a library collection used for imports."); print_usage_line(2, "Example: -collection:shared=dir/to/shared"); print_usage_line(2, "Usage in Code:"); print_usage_line(3, "import \"shared:foo\""); print_usage_line(0, ""); print_usage_line(1, "-define:="); - print_usage_line(2, "Defines a scalar boolean, integer or string as global constant"); + print_usage_line(2, "Defines a scalar boolean, integer or string as global constant."); print_usage_line(2, "Example: -define:SPAM=123"); print_usage_line(2, "To use: #config(SPAM, default_value)"); print_usage_line(0, ""); @@ -1739,69 +1739,69 @@ gb_internal void print_show_help(String const arg0, String const &command) { if (build) { print_usage_line(1, "-build-mode:"); - print_usage_line(2, "Sets the build mode"); + print_usage_line(2, "Sets the build mode."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-build-mode:exe Build as an executable"); - print_usage_line(3, "-build-mode:dll Build as a dynamically linked library"); - print_usage_line(3, "-build-mode:shared Build as a dynamically linked library"); - print_usage_line(3, "-build-mode:obj Build as an object file"); - print_usage_line(3, "-build-mode:object Build as an object file"); - print_usage_line(3, "-build-mode:assembly Build as an assembly file"); - print_usage_line(3, "-build-mode:assembler Build as an assembly file"); - print_usage_line(3, "-build-mode:asm Build as an assembly file"); - print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file"); - print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file"); + print_usage_line(3, "-build-mode:exe Build as an executable."); + print_usage_line(3, "-build-mode:dll Build as a dynamically linked library."); + print_usage_line(3, "-build-mode:shared Build as a dynamically linked library."); + print_usage_line(3, "-build-mode:obj Build as an object file."); + print_usage_line(3, "-build-mode:object Build as an object file."); + print_usage_line(3, "-build-mode:assembly Build as an assembly file."); + print_usage_line(3, "-build-mode:assembler Build as an assembly file."); + print_usage_line(3, "-build-mode:asm Build as an assembly file."); + print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file."); + print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-target:"); - print_usage_line(2, "Sets the target for the executable to be built in"); + print_usage_line(2, "Sets the target for the executable to be built in."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-debug"); - print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'"); + print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'."); print_usage_line(0, ""); print_usage_line(1, "-disable-assert"); - print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'"); + print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'."); print_usage_line(0, ""); print_usage_line(1, "-no-bounds-check"); - print_usage_line(2, "Disables bounds checking program wide"); + print_usage_line(2, "Disables bounds checking program wide."); print_usage_line(0, ""); print_usage_line(1, "-no-crt"); - print_usage_line(2, "Disables automatic linking with the C Run Time"); + print_usage_line(2, "Disables automatic linking with the C Run Time."); print_usage_line(0, ""); print_usage_line(1, "-no-thread-local"); - print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded"); + print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded."); print_usage_line(0, ""); print_usage_line(1, "-lld"); - print_usage_line(2, "Use the LLD linker rather than the default"); + print_usage_line(2, "Use the LLD linker rather than the default."); print_usage_line(0, ""); print_usage_line(1, "-use-separate-modules"); print_usage_line(1, "[EXPERIMENTAL]"); - print_usage_line(2, "The backend generates multiple build units which are then linked together"); - print_usage_line(2, "Normally, a single build unit is generated for a standard project"); + print_usage_line(2, "The backend generates multiple build units which are then linked together."); + print_usage_line(2, "Normally, a single build unit is generated for a standard project."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-no-threaded-checker"); - print_usage_line(2, "Disabled multithreading in the semantic checker stage"); + print_usage_line(2, "Disabled multithreading in the semantic checker stage."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-vet"); - print_usage_line(2, "Do extra checks on the code"); + print_usage_line(2, "Do extra checks on the code."); print_usage_line(2, "Extra checks include:"); print_usage_line(2, "-vet-unused"); print_usage_line(2, "-vet-shadowing"); @@ -1809,70 +1809,70 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-vet-unused"); - print_usage_line(2, "Checks for unused declarations"); + print_usage_line(2, "Checks for unused declarations."); print_usage_line(0, ""); print_usage_line(1, "-vet-shadowing"); - print_usage_line(2, "Checks for variable shadowing within procedures"); + print_usage_line(2, "Checks for variable shadowing within procedures."); print_usage_line(0, ""); print_usage_line(1, "-vet-using-stmt"); - print_usage_line(2, "Checks for the use of 'using' as a statement"); - print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); + print_usage_line(2, "Checks for the use of 'using' as a statement."); + print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring."); print_usage_line(0, ""); print_usage_line(1, "-vet-using-param"); - print_usage_line(2, "Checks for the use of 'using' on procedure parameters"); - print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); + print_usage_line(2, "Checks for the use of 'using' on procedure parameters."); + print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring."); print_usage_line(0, ""); print_usage_line(1, "-vet-style"); - print_usage_line(2, "Errs on missing trailing commas followed by a newline"); - print_usage_line(2, "Errs on deprecated syntax"); - print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)"); + print_usage_line(2, "Errs on missing trailing commas followed by a newline."); + print_usage_line(2, "Errs on deprecated syntax."); + print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)."); print_usage_line(0, ""); print_usage_line(1, "-vet-semicolon"); - print_usage_line(2, "Errs on unneeded semicolons"); + print_usage_line(2, "Errs on unneeded semicolons."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-ignore-unknown-attributes"); - print_usage_line(2, "Ignores unknown attributes"); - print_usage_line(2, "This can be used with metaprogramming tools"); + print_usage_line(2, "Ignores unknown attributes."); + print_usage_line(2, "This can be used with metaprogramming tools."); print_usage_line(0, ""); if (command != "test") { print_usage_line(1, "-no-entry-point"); - print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)"); + print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)."); print_usage_line(0, ""); } } if (test_only) { print_usage_line(1, "-test-name:"); - print_usage_line(2, "Run specific test only by name"); + print_usage_line(2, "Run specific test only by name."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-minimum-os-version:"); - print_usage_line(2, "Sets the minimum OS version targeted by the application"); + print_usage_line(2, "Sets the minimum OS version targeted by the application."); print_usage_line(2, "e.g. -minimum-os-version:12.0.0"); - print_usage_line(2, "(Only used when target is Darwin)"); + print_usage_line(2, "(Only used when target is Darwin.)"); print_usage_line(0, ""); print_usage_line(1, "-extra-linker-flags:"); - print_usage_line(2, "Adds extra linker specific flags in a string"); + print_usage_line(2, "Adds extra linker specific flags in a string."); print_usage_line(0, ""); print_usage_line(1, "-extra-assembler-flags:"); - print_usage_line(2, "Adds extra assembler specific flags in a string"); + print_usage_line(2, "Adds extra assembler specific flags in a string."); print_usage_line(0, ""); print_usage_line(1, "-microarch:"); - print_usage_line(2, "Specifies the specific micro-architecture for the build in a string"); + print_usage_line(2, "Specifies the specific micro-architecture for the build in a string."); print_usage_line(2, "Examples:"); print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:native"); @@ -1880,7 +1880,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-reloc-mode:"); - print_usage_line(2, "Specifies the reloc mode"); + print_usage_line(2, "Specifies the reloc mode."); print_usage_line(2, "Options:"); print_usage_line(3, "default"); print_usage_line(3, "static"); @@ -1889,65 +1889,65 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-disable-red-zone"); - print_usage_line(2, "Disable red zone on a supported freestanding target"); + print_usage_line(2, "Disable red zone on a supported freestanding target."); print_usage_line(0, ""); print_usage_line(1, "-dynamic-map-calls"); - print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution"); + print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-disallow-do"); - print_usage_line(2, "Disallows the 'do' keyword in the project"); + print_usage_line(2, "Disallows the 'do' keyword in the project."); print_usage_line(0, ""); print_usage_line(1, "-default-to-nil-allocator"); - print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing"); + print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing."); print_usage_line(0, ""); print_usage_line(1, "-strict-style"); - print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons"); - print_usage_line(2, "Errs on missing trailing commas followed by a newline"); - print_usage_line(2, "Errs on deprecated syntax"); + print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons."); + print_usage_line(2, "Errs on missing trailing commas followed by a newline."); + print_usage_line(2, "Errs on deprecated syntax."); print_usage_line(0, ""); print_usage_line(1, "-ignore-warnings"); - print_usage_line(2, "Ignores warning messages"); + print_usage_line(2, "Ignores warning messages."); print_usage_line(0, ""); print_usage_line(1, "-warnings-as-errors"); - print_usage_line(2, "Treats warning messages as error messages"); + print_usage_line(2, "Treats warning messages as error messages."); print_usage_line(0, ""); print_usage_line(1, "-terse-errors"); - print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line"); + print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line."); print_usage_line(0, ""); print_usage_line(1, "-error-pos-style:"); - print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)"); + print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)."); print_usage_line(2, "'odin' file/path(45:3)"); print_usage_line(2, "'unix' file/path:45:3:"); print_usage_line(0, ""); print_usage_line(1, "-max-error-count:"); - print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates"); - print_usage_line(2, "Must be an integer >0"); - print_usage_line(2, "If not set, the default max error count is %d", DEFAULT_MAX_ERROR_COLLECTOR_COUNT); + print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates."); + print_usage_line(2, "Must be an integer >0."); + print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT); print_usage_line(0, ""); print_usage_line(1, "-foreign-error-procedures"); - print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit"); + print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-sanitize:"); - print_usage_line(2, "Enables sanitization analysis"); - print_usage_line(2, "Options are 'address', 'memory', and 'thread'"); - print_usage_line(2, "NOTE: This flag can be used multiple times"); + print_usage_line(2, "Enables sanitization analysis."); + print_usage_line(2, "Options are 'address', 'memory', and 'thread'."); + print_usage_line(2, "NOTE: This flag can be used multiple times."); print_usage_line(0, ""); } @@ -1956,24 +1956,24 @@ gb_internal void print_show_help(String const arg0, String const &command) { #if defined(GB_SYSTEM_WINDOWS) print_usage_line(1, "-ignore-vs-search"); print_usage_line(2, "[Windows only]"); - print_usage_line(2, "Ignores the Visual Studio search for library paths"); + print_usage_line(2, "Ignores the Visual Studio search for library paths."); print_usage_line(0, ""); print_usage_line(1, "-resource:"); print_usage_line(2, "[Windows only]"); - print_usage_line(2, "Defines the resource file for the executable"); + print_usage_line(2, "Defines the resource file for the executable."); print_usage_line(2, "Example: -resource:path/to/file.rc"); print_usage_line(0, ""); print_usage_line(1, "-pdb-name:"); print_usage_line(2, "[Windows only]"); - print_usage_line(2, "Defines the generated PDB name when -debug is enabled"); + print_usage_line(2, "Defines the generated PDB name when -debug is enabled."); print_usage_line(2, "Example: -pdb-name:different.pdb"); print_usage_line(0, ""); print_usage_line(1, "-subsystem: