From aee895df0680838e8ea345966f6cafb36bebc840 Mon Sep 17 00:00:00 2001
From: StringNick <stringnickq@gmail.com>
Date: Tue, 3 Sep 2024 19:57:00 +0200
Subject: [PATCH] rm bips and bech and use it from bitcoin-zig

---
 build.zig                               |    7 +
 build.zig.zon                           |    4 +
 src/bech32/bech32.zig                   |  554 ------
 src/core/bip32/bip32.zig                |  774 ---------
 src/core/bip32/key.zig                  |   12 -
 src/core/bip32/utils.zig                |  182 --
 src/core/bip39/bip39.zig                |  352 ----
 src/core/bip39/language.zig             | 2124 -----------------------
 src/core/bip39/pbkdf2.zig               |  143 --
 src/core/lib.zig                        |    2 -
 src/core/nuts/nut02/nut02.zig           |    2 +-
 src/core/nuts/nut13/nut13.zig           |    4 +-
 src/lib.zig                             |    5 -
 src/mint/lightning/invoices/invoice.zig |    2 +-
 14 files changed, 15 insertions(+), 4152 deletions(-)
 delete mode 100644 src/bech32/bech32.zig
 delete mode 100644 src/core/bip32/bip32.zig
 delete mode 100644 src/core/bip32/key.zig
 delete mode 100644 src/core/bip32/utils.zig
 delete mode 100644 src/core/bip39/bip39.zig
 delete mode 100644 src/core/bip39/language.zig
 delete mode 100644 src/core/bip39/pbkdf2.zig

diff --git a/build.zig b/build.zig
index 82a799a..c18f104 100644
--- a/build.zig
+++ b/build.zig
@@ -66,6 +66,11 @@ pub fn build(b: *std.Build) !void {
         .optimize = optimize,
     });
 
+    const bitcoin_zig = b.dependency("bitcoin-zig", .{
+        .target = target,
+        .optimize = optimize,
+    });
+
     const base58_module = b.dependency("base58-zig", .{
         .target = target,
         .optimize = optimize,
@@ -190,6 +195,7 @@ pub fn build(b: *std.Build) !void {
     lib_unit_tests.root_module.addImport("secp256k1", secp256k1.module("secp256k1"));
     lib_unit_tests.root_module.linkLibrary(secp256k1.artifact("libsecp"));
     lib_unit_tests.root_module.addImport("httpz", httpz_module);
+    lib_unit_tests.root_module.addImport("bitcoin", bitcoin_zig.module("bitcoin"));
     lib_unit_tests.root_module.addImport("base58", base58_module);
 
     const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
@@ -214,6 +220,7 @@ pub fn build(b: *std.Build) !void {
     bench.root_module.addImport("zul", zul);
     bench.root_module.addImport("secp256k1", secp256k1.module("secp256k1"));
     bench.root_module.linkLibrary(secp256k1.artifact("libsecp"));
+    bench.root_module.addImport("bitcoin", bitcoin_zig.module("bitcoin"));
 
     const run_bench = b.addRunArtifact(bench);
 
diff --git a/build.zig.zon b/build.zig.zon
index 929c485..fa3bf1b 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -47,6 +47,10 @@
             .url = "https://github.com/zig-bitcoin/libsecp256k1-zig/archive/5f70bc5aa2a5ebc69c78a9a75fb83c2d7035bde1.zip",
             .hash = "12208e2a2f181feabb9fa01db64232e9cdefdf1b8f2919f1dd7f24c2393cad2b947b",
         },
+        .@"bitcoin-zig" = .{
+            .url = "git+https://github.com/zig-bitcoin/bitcoin-zig#f3af13008b088796697fc656e26d8c2ddf73dc18",
+            .hash = "1220d90650e0907125bc6035e3e10e10c088e9eb4de958b343a3cce5d7209ee5bbd4",
+        },
     },
     .paths = .{
         "build.zig",
diff --git a/src/bech32/bech32.zig b/src/bech32/bech32.zig
deleted file mode 100644
index e9b4aa8..0000000
--- a/src/bech32/bech32.zig
+++ /dev/null
@@ -1,554 +0,0 @@
-const std = @import("std");
-
-const Case = enum {
-    upper,
-    lower,
-    none,
-};
-
-/// Check if the HRP is valid. Returns the case of the HRP, if any.
-///
-/// # Errors
-/// * **MixedCase**: If the HRP contains both uppercase and lowercase characters.
-/// * **InvalidChar**: If the HRP contains any non-ASCII characters (outside 33..=126).
-/// * **InvalidLength**: If the HRP is outside 1..83 characters long.
-fn checkHrp(hrp: []const u8) Error!Case {
-    if (hrp.len == 0 or hrp.len > 83) return Error.InvalidLength;
-
-    var has_lower: bool = false;
-    var has_upper: bool = false;
-
-    for (hrp) |b| {
-        // Valid subset of ASCII
-        if (!(b >= 33 and b <= 126)) return Error.InvalidChar;
-
-        if (b >= 'a' and b <= 'z') has_lower = true else if (b >= 'A' and b <= 'Z') has_upper = true;
-
-        if (has_lower and has_upper) return Error.MixedCase;
-    }
-    if (has_upper) return .upper;
-    if (has_lower) return .lower;
-
-    return .none;
-}
-
-fn verifyChecksum(allocator: std.mem.Allocator, hrp: []const u8, data: []const u5) Error!?Variant {
-    var exp = try hrpExpand(allocator, hrp);
-    defer exp.deinit();
-
-    try exp.appendSlice(data);
-    return Variant.fromRemainder(polymod(exp.items));
-}
-
-fn hrpExpand(allocator: std.mem.Allocator, hrp: []const u8) Error!std.ArrayList(u5) {
-    var v = std.ArrayList(u5).init(allocator);
-    errdefer v.deinit();
-
-    for (hrp) |b| {
-        try v.append(@truncate(b >> 5));
-    }
-
-    try v.append(0);
-
-    for (hrp) |b| {
-        try v.append(@truncate(b & 0x1f));
-    }
-
-    return v;
-}
-
-/// Generator coefficients
-const GEN: [5]u32 = .{
-    0x3b6a_57b2,
-    0x2650_8e6d,
-    0x1ea1_19fa,
-    0x3d42_33dd,
-    0x2a14_62b3,
-};
-
-fn polymod(values: []const u5) u32 {
-    var chk: u32 = 1;
-    var b: u8 = undefined;
-    for (values) |v| {
-        b = @truncate(chk >> 25);
-        chk = (chk & 0x01ff_ffff) << 5 ^ @as(u32, v);
-
-        for (GEN, 0..) |item, i| {
-            if (std.math.shr(u8, b, i) & 1 == 1) {
-                chk ^= item;
-            }
-        }
-    }
-
-    return chk;
-}
-
-/// Human-readable part and data part separator
-const SEP: u8 = '1';
-
-/// Encoding character set. Maps data value -> char
-const CHARSET: [32]u8 = .{
-    'q', 'p', 'z', 'r', 'y', '9', 'x', '8', //  +0
-    'g', 'f', '2', 't', 'v', 'd', 'w', '0', //  +8
-    's', '3', 'j', 'n', '5', '4', 'k', 'h', // +16
-    'c', 'e', '6', 'm', 'u', 'a', '7', 'l', // +24
-};
-
-/// Reverse character set. Maps ASCII byte -> CHARSET index on [0,31]
-const CHARSET_REV: [128]i8 = .{
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    15, -1, 10, 17, 21, 20, 26, 30, 7,  5,  -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9,  8,
-    23, -1, 18, 22, 31, 27, 19, -1, 1,  0,  3,  16, 11, 28, 12, 14, 6,  4,  2,  -1, -1, -1, -1, -1,
-    -1, 29, -1, 24, 13, 25, 9,  8,  23, -1, 18, 22, 31, 27, 19, -1, 1,  0,  3,  16, 11, 28, 12, 14,
-    6,  4,  2,  -1, -1, -1, -1, -1,
-};
-
-/// Error types for Bech32 encoding / decoding
-pub const Error = std.mem.Allocator.Error || error{
-    /// String does not contain the separator character
-    MissingSeparator,
-    /// The checksum does not match the rest of the data
-    InvalidChecksum,
-    /// The data or human-readable part is too long or too short
-    InvalidLength,
-    /// Some part of the string contains an invalid character
-    InvalidChar,
-    /// Some part of the data has an invalid value
-    InvalidData,
-    /// The bit conversion failed due to a padding issue
-    InvalidPadding,
-    /// The whole string must be of one case
-    MixedCase,
-};
-
-const BECH32_CONST: u32 = 1;
-const BECH32M_CONST: u32 = 0x2bc8_30a3;
-
-/// Used for encode/decode operations for the two variants of Bech32
-pub const Variant = enum {
-    /// The original Bech32 described in [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)
-    bech32,
-    /// The improved Bech32m variant described in [BIP-0350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki)
-    bech32m,
-
-    // Produce the variant based on the remainder of the polymod operation
-    fn fromRemainder(c: u32) ?Variant {
-        return switch (c) {
-            BECH32_CONST => .bech32,
-            BECH32M_CONST => .bech32m,
-            else => null,
-        };
-    }
-
-    fn constant(self: Variant) u32 {
-        return switch (self) {
-            .bech32 => BECH32_CONST,
-            .bech32m => BECH32M_CONST,
-        };
-    }
-};
-
-/// Decode a bech32 string into the raw HRP and the `u5` data.
-fn splitAndDecode(allocator: std.mem.Allocator, s: []const u8) Error!struct { std.ArrayList(u8), std.ArrayList(u5) } {
-    // Split at separator and check for two pieces
-
-    const raw_hrp, const raw_data = if (std.mem.indexOfScalar(u8, s, SEP)) |sep| .{
-        s[0..sep], s[sep + 1 ..],
-    } else return Error.MissingSeparator;
-
-    var case = try checkHrp(raw_hrp);
-    var buf = try std.ArrayList(u8).initCapacity(allocator, 100);
-    errdefer buf.deinit();
-
-    const hrp_lower = switch (case) {
-        .upper => std.ascii.lowerString(buf.items, raw_hrp),
-        // already lowercase
-        .lower, .none => v: {
-            try buf.appendSlice(raw_hrp);
-            break :v buf.items;
-        },
-    };
-
-    buf.items.len = hrp_lower.len;
-
-    var data = std.ArrayList(u5).init(allocator);
-    errdefer data.deinit();
-
-    // Check data payload
-    for (raw_data) |c| {
-        // Only check if c is in the ASCII range, all invalid ASCII
-        // characters have the value -1 in CHARSET_REV (which covers
-        // the whole ASCII range) and will be filtered out later.
-        if (!std.ascii.isAscii(c)) return error.InvalidChar;
-
-        if (std.ascii.isLower(c)) {
-            switch (case) {
-                .upper => return Error.MixedCase,
-                .none => case = .lower,
-                .lower => {},
-            }
-        } else if (std.ascii.isUpper(c)) {
-            switch (case) {
-                .lower => return Error.MixedCase,
-                .none => case = .upper,
-                .upper => {},
-            }
-        }
-
-        // c should be <128 since it is in the ASCII range, CHARSET_REV.len() == 128
-        const num_value = CHARSET_REV[c];
-
-        if (!(0 >= num_value or num_value <= 31)) return Error.InvalidChar;
-
-        try data.append(@intCast(num_value));
-    }
-
-    return .{ buf, data };
-}
-
-const CHECKSUM_LENGTH: usize = 6;
-
-/// Decode a bech32 string into the raw HRP and the data bytes.
-///
-/// Returns the HRP in lowercase, the data with the checksum removed, and the encoding.
-pub fn decode(allocator: std.mem.Allocator, s: []const u8) Error!struct { std.ArrayList(u8), std.ArrayList(u5), Variant } {
-    const hrp_lower, var data = try splitAndDecode(allocator, s);
-    errdefer data.deinit();
-    errdefer hrp_lower.deinit();
-
-    if (data.items.len < CHECKSUM_LENGTH)
-        return Error.InvalidLength;
-
-    if (try verifyChecksum(allocator, hrp_lower.items, data.items)) |v| {
-        // Remove checksum from data payload
-        data.items.len = data.items.len - CHECKSUM_LENGTH;
-
-        return .{ hrp_lower, data, v };
-    }
-    return Error.InvalidChecksum;
-}
-
-/// Encode a bech32 payload to an [WriteAny].
-///
-/// # Errors
-/// * If [checkHrp] returns an error for the given HRP.
-/// # Deviations from standard
-/// * No length limits are enforced for the data part
-pub fn encodeToFmt(
-    allocator: std.mem.Allocator,
-    fmt: std.io.AnyWriter,
-    hrp: []const u8,
-    data: []const u5,
-    variant: Variant,
-) !void {
-    var hrp_lower = try std.ArrayList(u8).initCapacity(allocator, hrp.len);
-    defer hrp_lower.deinit();
-
-    hrp_lower.appendSliceAssumeCapacity(hrp);
-
-    _ = if (try checkHrp(hrp) == .upper) std.ascii.lowerString(hrp_lower.items, hrp);
-
-    var writer = try Bech32Writer.init(hrp_lower.items, variant, fmt);
-
-    try writer.write(data);
-    try writer.finalize();
-}
-
-/// Allocationless Bech32 writer that accumulates the checksum data internally and writes them out
-/// in the end.
-pub const Bech32Writer = struct {
-    formatter: std.io.AnyWriter,
-    chk: u32,
-    variant: Variant,
-
-    /// Creates a new writer that can write a bech32 string without allocating itself.
-    ///
-    /// This is a rather low-level API and doesn't check the HRP or data length for standard
-    /// compliance.
-    pub fn init(hrp: []const u8, variant: Variant, fmt: std.io.AnyWriter) !Bech32Writer {
-        var writer = Bech32Writer{
-            .formatter = fmt,
-            .chk = 1,
-            .variant = variant,
-        };
-
-        _ = try writer.formatter.write(hrp);
-        try writer.formatter.writeByte(SEP);
-
-        // expand HRP
-        for (hrp) |b| {
-            writer.polymodStep(@truncate(b >> 5));
-        }
-
-        writer.polymodStep(0);
-        for (hrp) |b| {
-            writer.polymodStep(@truncate(b & 0x1f));
-        }
-
-        return writer;
-    }
-
-    fn polymodStep(self: *@This(), v: u5) void {
-        const b: u8 = @truncate(self.chk >> 25);
-
-        self.chk = (self.chk & 0x01ff_ffff) << 5 ^ v;
-
-        for (0.., GEN) |i, item| {
-            if (std.math.shr(u8, b, i) & 1 == 1) {
-                self.chk ^= item;
-            }
-        }
-    }
-
-    pub fn finalize(self: *@This()) !void {
-        try self.writeChecksum();
-    }
-
-    fn writeChecksum(self: *@This()) !void {
-        // Pad with 6 zeros
-        for (0..CHECKSUM_LENGTH) |_| {
-            self.polymodStep(0);
-        }
-
-        const plm: u32 = self.chk ^ self.variant.constant();
-
-        for (0..CHECKSUM_LENGTH) |p| {
-            const v: u8 = @intCast(std.math.shr(u32, plm, (5 * (5 - p))) & 0x1f);
-
-            try self.formatter.writeByte(CHARSET[v]);
-        }
-    }
-
-    /// Write a `u5` slice
-    fn write(self: *@This(), data: []const u5) !void {
-        for (data) |b| {
-            try self.writeU5(b);
-        }
-    }
-
-    /// Writes a single 5 bit value of the data part
-    fn writeU5(self: *@This(), data: u5) !void {
-        self.polymodStep(data);
-
-        try self.formatter.writeByte(CHARSET[data]);
-    }
-};
-
-// Encode a bech32 payload to string.
-//
-// # Errors
-// * If [check_hrp] returns an error for the given HRP.
-// # Deviations from standard
-// * No length limits are enforced for the data part
-pub fn encode(allocator: std.mem.Allocator, hrp: []const u8, data: []const u5, variant: Variant) !std.ArrayList(u8) {
-    var buf = std.ArrayList(u8).init(allocator);
-    errdefer buf.deinit();
-
-    try encodeToFmt(allocator, buf.writer().any(), hrp, data, variant);
-
-    return buf;
-}
-
-pub fn toBase32(allocator: std.mem.Allocator, d: []const u8) !std.ArrayList(u5) {
-    var self = std.ArrayList(u5).init(allocator);
-    errdefer self.deinit();
-
-    // Amount of bits left over from last round, stored in buffer.
-    var buffer_bits: u32 = 0;
-    // Holds all unwritten bits left over from last round. The bits are stored beginning from
-    // the most significant bit. E.g. if buffer_bits=3, then the byte with bits a, b and c will
-    // look as follows: [a, b, c, 0, 0, 0, 0, 0]
-    var buffer: u8 = 0;
-
-    for (d) |b| {
-        // Write first u5 if we have to write two u5s this round. That only happens if the
-        // buffer holds too many bits, so we don't have to combine buffer bits with new bits
-        // from this rounds byte.
-        if (buffer_bits >= 5) {
-            try self.append(@truncate(std.math.shr(u8, buffer & 0b1111_1000, 3)));
-            buffer <<= 5;
-            buffer_bits -= 5;
-        }
-
-        // Combine all bits from buffer with enough bits from this rounds byte so that they fill
-        // a u5. Save reamining bits from byte to buffer.
-        const from_buffer = buffer >> 3;
-        const from_byte = std.math.shr(u8, b, 3 + buffer_bits); // buffer_bits <= 4
-
-        try self.append(@truncate(from_buffer | from_byte));
-        buffer = std.math.shl(u8, b, 5 - buffer_bits);
-        buffer_bits += 3;
-    }
-
-    // There can be at most two u5s left in the buffer after processing all bytes, write them.
-    if (buffer_bits >= 5) {
-        try self.append(@truncate((buffer & 0b1111_1000) >> 3));
-        buffer <<= 5;
-        buffer_bits -= 5;
-    }
-
-    if (buffer_bits != 0) {
-        try self.append(@truncate(buffer >> 3));
-    }
-
-    return self;
-}
-
-/// Encode a bech32 payload without a checksum to an [std.io.AnyWriter].
-///
-/// # Errors
-/// * If [checkHrp] returns an error for the given HRP.
-/// # Deviations from standard
-/// * No length limits are enforced for the data part
-pub fn encodeWithoutChecksumToFmt(
-    allocator: std.mem.Allocator,
-    fmt: std.io.AnyWriter,
-    hrp: []const u8,
-    data: []const u5,
-) !void {
-    var hrp_lower = try std.ArrayList(u8).initCapacity(allocator, hrp.len);
-    defer hrp_lower.deinit();
-
-    hrp_lower.appendSliceAssumeCapacity(hrp);
-
-    _ = if (try checkHrp(hrp) == .upper) std.ascii.lowerString(hrp_lower.items, hrp);
-
-    _ = try fmt.write(hrp);
-
-    _ = try fmt.writeByte(SEP);
-
-    for (data) |b| {
-        try fmt.writeByte(CHARSET[b]);
-    }
-}
-
-/// Encode a bech32 payload to string without the checksum.
-///
-/// # Errors
-/// * If [checkHrp] returns an error for the given HRP.
-/// # Deviations from standard
-/// * No length limits are enforced for the data part
-pub fn encodeWithoutChecksum(allocator: std.mem.Allocator, hrp: []const u8, data: []const u5) !std.ArrayList(u8) {
-    var buf = std.ArrayList(u8).init(allocator);
-    errdefer buf.deinit();
-
-    try encodeWithoutChecksumToFmt(allocator, buf.writer().any(), hrp, data);
-
-    return buf;
-}
-
-/// Decode a bech32 string into the raw HRP and the data bytes, assuming no checksum.
-///
-/// Returns the HRP in lowercase and the data.
-pub fn decodeWithoutChecksum(allocator: std.mem.Allocator, s: []const u8) Error!struct { std.ArrayList(u8), std.ArrayList(u5) } {
-    return splitAndDecode(allocator, s);
-}
-
-/// Convert base32 to base256, removes null-padding if present, returns
-/// `Err(Error::InvalidPadding)` if padding bits are unequal `0`
-pub fn arrayListFromBase32(allocator: std.mem.Allocator, b: []const u5) !std.ArrayList(u8) {
-    return convertBits(u5, allocator, b, 5, 8, false);
-}
-
-/// Convert between bit sizes
-///
-/// # Errors
-/// * `Error::InvalidData` if any element of `data` is out of range
-/// * `Error::InvalidPadding` if `pad == false` and the padding bits are not `0`
-///
-/// # Panics
-/// Function will panic if attempting to convert `from` or `to` a bit size that
-/// is 0 or larger than 8 bits.
-///
-/// # Examples
-///
-/// ```zig
-/// const base5 = try convertBits(u8, allocator, &.{0xff}, 8, 5, true);
-/// std.testing.expectEqualSlices(u8, base5.items, &.{0x1f, 0x1c});
-/// ```
-pub fn convertBits(comptime T: type, allocator: std.mem.Allocator, data: []const T, from: u32, to: u32, pad: bool) !std.ArrayList(u8) {
-    if (from > 8 or to > 8 or from == 0 or to == 0) {
-        @panic("convert_bits `from` and `to` parameters 0 or greater than 8");
-    }
-
-    var acc: u32 = 0;
-    var bits: u32 = 0;
-    var ret = std.ArrayList(u8).init(allocator);
-    errdefer ret.deinit();
-
-    const maxv: u32 = std.math.shl(u32, 1, to) - 1;
-    for (data) |value| {
-        const v: u32 = @intCast(value);
-        if (std.math.shr(u32, v, from) != 0) {
-            // Input value exceeds `from` bit size
-            return error.InvalidData;
-        }
-        acc = std.math.shl(u32, acc, from) | v;
-        bits += from;
-
-        while (bits >= to) {
-            bits -= to;
-            try ret.append(@truncate(std.math.shr(u32, acc, bits) & maxv));
-        }
-    }
-
-    if (pad) {
-        if (bits > 0) {
-            try ret.append(@truncate(std.math.shl(u32, acc, to - bits) & maxv));
-        }
-    } else if (bits >= from or (std.math.shl(u32, acc, to - bits) & maxv) != 0) {
-        return error.InvalidPadding;
-    }
-
-    return ret;
-}
-
-test "encode" {
-    try std.testing.expectError(
-        error.InvalidLength,
-        encode(std.testing.allocator, "", &.{ 1, 2, 3, 4 }, .bech32),
-    );
-}
-
-test "roundtrip_without_checksum" {
-    const hrp = "lnbc";
-    const data = try toBase32(std.testing.allocator, "Hello World!");
-    defer data.deinit();
-
-    const encoded = try encodeWithoutChecksum(std.testing.allocator, hrp, data.items);
-    defer encoded.deinit();
-
-    const decoded_hrp, const decoded_data =
-        try decodeWithoutChecksum(std.testing.allocator, encoded.items);
-    defer decoded_hrp.deinit();
-    defer decoded_data.deinit();
-
-    try std.testing.expectEqualSlices(u8, hrp, decoded_hrp.items);
-
-    try std.testing.expectEqualSlices(u5, data.items, decoded_data.items);
-}
-
-test "test_hrp_case_decode" {
-    const hrp, const data, const variant = try decode(std.testing.allocator, "hrp1qqqq40atq3");
-    defer hrp.deinit();
-    defer data.deinit();
-
-    var expected_data = try toBase32(std.testing.allocator, &.{ 0x00, 0x00 });
-    defer expected_data.deinit();
-
-    try std.testing.expectEqual(.bech32, variant);
-    try std.testing.expectEqualSlices(u8, "hrp", hrp.items);
-    try std.testing.expectEqualSlices(u5, expected_data.items, data.items);
-}
-
-test "test_hrp_case" {
-    var data = try toBase32(std.testing.allocator, &.{ 0x00, 0x00 });
-    defer data.deinit();
-
-    // Tests for issue with HRP case checking being ignored for encoding
-    const encoded = try encode(std.testing.allocator, "HRP", data.items, .bech32);
-    defer encoded.deinit();
-
-    try std.testing.expectEqualSlices(u8, "hrp1qqqq40atq3", encoded.items);
-}
diff --git a/src/core/bip32/bip32.zig b/src/core/bip32/bip32.zig
deleted file mode 100644
index 3804f28..0000000
--- a/src/core/bip32/bip32.zig
+++ /dev/null
@@ -1,774 +0,0 @@
-//! BIP32 implementation.
-//!
-//! Implementation of BIP32 hierarchical deterministic wallets, as defined
-//! at <https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki>.
-//!
-const Ripemd160 = @import("../../mint/lightning/invoices/ripemd160.zig").Ripemd160;
-const secp256k1 = @import("secp256k1");
-const Secp256k1NumberOfPoints = 115792089237316195423570985008687907852837564279074904382605163141518161494337;
-const key_lib = @import("key.zig");
-
-const base58 = @import("base58");
-
-const std = @import("std");
-const Hmac = std.crypto.auth.hmac.sha2.HmacSha512;
-
-pub const Network = enum { MAINNET, TESTNET, REGTEST, SIMNET };
-
-pub const SerializedPrivateKeyVersion = enum(u32) {
-    MAINNET = 0x0488aDe4,
-    TESTNET = 0x04358394,
-    SEGWIT_MAINNET = 0x04b2430c,
-    SEGWIT_TESTNET = 0x045f18bc,
-};
-
-pub const SerializedPublicKeyVersion = enum(u32) {
-    MAINNET = 0x0488b21e,
-    TESTNET = 0x043587cf,
-    SEGWIT_MAINNET = 0x04b24746,
-    SEGWIT_TESTNET = 0x045f1cf6,
-};
-
-/// A chain code
-pub const ChainCode = struct {
-    inner: [32]u8,
-
-    fn fromHmac(hmac: [64]u8) ChainCode {
-        return .{ .inner = hmac[32..].* };
-    }
-};
-
-/// A fingerprint
-pub const Fingerprint = struct {
-    inner: [4]u8,
-};
-
-fn base58EncodeCheck(allocator: std.mem.Allocator, data: []const u8) ![]u8 {
-    const encoder = base58.Encoder.init(.{});
-
-    var hasher = std.crypto.hash.sha2.Sha256.init(.{});
-    hasher.update(data);
-    var checksum = hasher.finalResult();
-
-    hasher = std.crypto.hash.sha2.Sha256.init(.{});
-    hasher.update(&checksum);
-    checksum = hasher.finalResult();
-
-    var encoding_data = try allocator.alloc(u8, data.len + 4);
-    defer allocator.free(encoding_data);
-
-    @memcpy(encoding_data[0..data.len], data);
-    @memcpy(encoding_data[data.len..], checksum[0..4]);
-
-    return try encoder.encodeAlloc(allocator, encoding_data);
-}
-
-fn base58DecodeCheck(allocator: std.mem.Allocator, data: []const u8) ![]u8 {
-    const decoder = base58.Decoder.init(.{});
-
-    const decoded = try decoder.decodeAlloc(allocator, data);
-    defer allocator.free(decoded);
-    if (decoded.len < 4) return error.TooShortError;
-
-    const check_start = decoded.len - 4;
-
-    var hasher = std.crypto.hash.sha2.Sha256.init(.{});
-
-    hasher.update(decoded[0..check_start]);
-    const fr = hasher.finalResult();
-
-    hasher = std.crypto.hash.sha2.Sha256.init(.{});
-    hasher.update(&fr);
-
-    const hash_check = hasher.finalResult()[0..4].*;
-    const data_check = decoded[check_start..][0..4].*;
-
-    const expected = std.mem.readInt(u32, &hash_check, .little);
-    const actual = std.mem.readInt(u32, &data_check, .little);
-
-    if (expected != actual) return error.IncorrectChecksum;
-
-    const result = try allocator.alloc(u8, check_start);
-    errdefer allocator.free(result);
-
-    @memcpy(result, decoded[0..check_start]);
-    return result;
-}
-
-/// Extended private key
-pub const ExtendedPrivKey = struct {
-    /// The network this key is to be used on
-    network: Network,
-    /// How many derivations this key is from the master (which is 0)
-    depth: u8,
-    /// Fingerprint of the parent key (0 for master)
-    parent_fingerprint: Fingerprint,
-    /// Child number of the key used to derive from parent (0 for master)
-    child_number: ChildNumber,
-    /// Private key
-    private_key: secp256k1.SecretKey,
-    /// Chain code
-    chain_code: ChainCode,
-
-    pub fn fromStr(allocator: std.mem.Allocator, s: []const u8) !ExtendedPrivKey {
-        const decoded = try base58DecodeCheck(allocator, s);
-        defer allocator.free(decoded);
-
-        if (decoded.len != 78) return error.InvalidLength;
-
-        return try decode(decoded);
-    }
-
-    pub fn toStr(self: ExtendedPrivKey, allocator: std.mem.Allocator) ![]const u8 {
-        const encoded = self.encode();
-        return base58EncodeCheck(allocator, &encoded);
-    }
-
-    /// Extended private key binary encoding according to BIP 32
-    pub fn encode(self: ExtendedPrivKey) [78]u8 {
-        var ret = [_]u8{0} ** 78;
-
-        ret[0..4].* = switch (self.network) {
-            .MAINNET => .{ 0x04, 0x88, 0xAD, 0xE4 },
-            else => .{ 0x04, 0x35, 0x83, 0x94 },
-        };
-
-        ret[4] = self.depth;
-        ret[5..9].* = self.parent_fingerprint.inner;
-
-        var buf: [4]u8 = undefined;
-        std.mem.writeInt(u32, &buf, self.child_number.toU32(), .big);
-
-        ret[9..13].* = buf;
-        ret[13..45].* = self.chain_code.inner;
-        ret[45] = 0;
-        ret[46..78].* = self.private_key.data;
-        return ret;
-    }
-
-    /// Construct a new master key from a seed value
-    pub fn initMaster(network: Network, seed: []const u8) !ExtendedPrivKey {
-        var hmac_engine = Hmac.init("Bitcoin seed");
-        hmac_engine.update(seed);
-        var hmac_result: [Hmac.mac_length]u8 = undefined;
-
-        hmac_engine.final(&hmac_result);
-
-        return ExtendedPrivKey{
-            .network = network,
-            .depth = 0,
-            .parent_fingerprint = .{ .inner = .{ 0, 0, 0, 0 } },
-            .child_number = try ChildNumber.fromNormalIdx(0),
-            .private_key = try secp256k1.SecretKey.fromSlice(hmac_result[0..32]),
-            .chain_code = ChainCode.fromHmac(hmac_result),
-        };
-    }
-
-    /// Constructs ECDSA compressed private key matching internal secret key representation.
-    pub fn toPrivateKey(self: ExtendedPrivKey) key_lib.PrivateKey {
-        return .{
-            .compressed = true,
-            .network = self.network,
-            .inner = self.private_key,
-        };
-    }
-
-    /// Constructs BIP340 keypair for Schnorr signatures and Taproot use matching the internal
-    /// secret key representation.
-    pub fn toKeypair(self: ExtendedPrivKey, secp: secp256k1.Secp256k1) secp256k1.KeyPair {
-        return secp256k1.KeyPair.fromSecretKey(&secp, &self.private_key) catch @panic("BIP32 internal private key representation is broken");
-    }
-
-    /// Private->Private child key derivation
-    pub fn ckdPriv(
-        self: ExtendedPrivKey,
-        secp: secp256k1.Secp256k1,
-        i: ChildNumber,
-    ) !ExtendedPrivKey {
-        var hmac_engine = Hmac.init(self.chain_code.inner[0..]);
-        switch (i) {
-            .normal => {
-                // Non-hardened key: compute public data and use that
-                hmac_engine.update(&self.private_key.publicKey(secp).serialize());
-            },
-            .hardened => {
-                // Hardened key: use only secret data to prevent public derivation
-                hmac_engine.update(&.{0});
-                hmac_engine.update(self.private_key.data[0..]);
-            },
-        }
-
-        const i_u32 = i.toU32();
-        var buf: [4]u8 = undefined;
-
-        std.mem.writeInt(u32, &buf, i_u32, .big);
-
-        hmac_engine.update(&buf);
-
-        var hmac_result: [Hmac.mac_length]u8 = undefined;
-
-        hmac_engine.final(&hmac_result);
-
-        const sk = secp256k1.SecretKey.fromSlice(hmac_result[0..32]) catch @panic("statistically impossible to hit");
-        const tweaked = sk.addTweak(secp256k1.Scalar.fromSecretKey(self.private_key)) catch @panic("statistically impossible to hit");
-
-        return .{
-            .network = self.network,
-            .depth = self.depth + 1,
-            .parent_fingerprint = self.fingerprint(secp),
-            .child_number = i,
-            .private_key = tweaked,
-            .chain_code = ChainCode.fromHmac(hmac_result),
-        };
-    }
-
-    /// Attempts to derive an extended private key from a path.
-    ///
-    /// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
-    pub fn derivePriv(
-        self: ExtendedPrivKey,
-        secp: secp256k1.Secp256k1,
-        path: []const ChildNumber,
-    ) !ExtendedPrivKey {
-        var sk = self;
-        for (path) |cnum| {
-            sk = try sk.ckdPriv(secp, cnum);
-        }
-
-        return sk;
-    }
-
-    /// Returns the HASH160 of the public key belonging to the xpriv
-    pub fn identifier(self: ExtendedPrivKey, secp: secp256k1.Secp256k1) XpubIdentifier {
-        return ExtendedPubKey.fromPrivateKey(secp, self).identifier();
-    }
-
-    /// Returns the first four bytes of the identifier
-    pub fn fingerprint(self: ExtendedPrivKey, secp: secp256k1.Secp256k1) Fingerprint {
-        return .{ .inner = self.identifier(secp).inner[0..4].* };
-    }
-
-    /// Decoding extended private key from binary data according to BIP 32
-    pub fn decode(data: []const u8) !ExtendedPrivKey {
-        if (data.len != 78) {
-            return error.WrongExtendedKeyLength;
-        }
-
-        const network = if (std.mem.eql(u8, data[0..4], &.{ 0x04, 0x88, 0xAD, 0xE4 }))
-            Network.MAINNET
-        else if (std.mem.eql(u8, data[0..4], &.{ 0x04, 0x35, 0x83, 0x94 }))
-            Network.TESTNET
-        else
-            return error.UnknownVersion;
-
-        return .{
-            .network = network,
-            .depth = data[4],
-            .parent_fingerprint = .{ .inner = data[5..9].* },
-            .child_number = ChildNumber.fromU32(std.mem.readInt(u32, data[9..13], .big)),
-            .chain_code = .{ .inner = data[13..45].* },
-            .private_key = try secp256k1.SecretKey.fromSlice(data[46..78]),
-        };
-    }
-};
-
-/// Extended public key
-pub const ExtendedPubKey = struct {
-    /// The network this key is to be used on
-    network: Network,
-    /// How many derivations this key is from the master (which is 0)
-    depth: u8,
-    /// Fingerprint of the parent key
-    parent_fingerprint: Fingerprint,
-    /// Child number of the key used to derive from parent (0 for master)
-    child_number: ChildNumber,
-    /// Public key
-    public_key: secp256k1.PublicKey,
-    /// Chain code
-    chain_code: ChainCode,
-
-    pub fn fromStr(allocator: std.mem.Allocator, s: []const u8) !ExtendedPubKey {
-        const decoded = try base58DecodeCheck(allocator, s);
-        defer allocator.free(decoded);
-
-        if (decoded.len != 78) return error.InvalidLength;
-
-        return try decode(decoded);
-    }
-
-    pub fn toStr(self: ExtendedPubKey, allocator: std.mem.Allocator) ![]const u8 {
-        return try base58EncodeCheck(allocator, &self.encode());
-    }
-
-    /// Extended public key binary encoding according to BIP 32
-    pub fn encode(self: ExtendedPubKey) [78]u8 {
-        var ret = [_]u8{0} ** 78;
-
-        ret[0..4].* = switch (self.network) {
-            .MAINNET => .{ 0x04, 0x88, 0xB2, 0x1E },
-            else => .{ 0x04, 0x35, 0x87, 0xCF },
-        };
-
-        ret[4] = self.depth;
-        ret[5..9].* = self.parent_fingerprint.inner;
-
-        var buf: [4]u8 = undefined;
-        std.mem.writeInt(u32, &buf, self.child_number.toU32(), .big);
-
-        ret[9..13].* = buf;
-        ret[13..45].* = self.chain_code.inner;
-        ret[45..78].* = self.public_key.serialize();
-        return ret;
-    }
-
-    pub fn decode(data: []const u8) !ExtendedPubKey {
-        if (data.len != 78) {
-            return error.WrongExtendedKeyLength;
-        }
-
-        const network = if (std.mem.eql(u8, data[0..4], &.{ 0x04, 0x88, 0xB2, 0x1E }))
-            Network.MAINNET
-        else if (std.mem.eql(u8, data[0..4], &.{ 0x04, 0x35, 0x87, 0xCF }))
-            Network.TESTNET
-        else
-            return error.UnknownVersion;
-
-        return .{
-            .network = network,
-            .depth = data[4],
-            .parent_fingerprint = .{ .inner = data[5..9].* },
-            .child_number = ChildNumber.fromU32(std.mem.readInt(u32, data[9..13], .big)),
-            .chain_code = .{ .inner = data[13..45].* },
-            .public_key = try secp256k1.PublicKey.fromSlice(data[45..78]),
-        };
-    }
-
-    /// Derives a public key from a private key
-    pub fn fromPrivateKey(
-        secp: secp256k1.Secp256k1,
-        sk: ExtendedPrivKey,
-    ) ExtendedPubKey {
-        return .{
-            .network = sk.network,
-            .depth = sk.depth,
-            .parent_fingerprint = sk.parent_fingerprint,
-            .child_number = sk.child_number,
-            .public_key = sk.private_key.publicKey(secp),
-            .chain_code = sk.chain_code,
-        };
-    }
-
-    /// Attempts to derive an extended public key from a path.
-    ///
-    /// The `path` argument can be any type implementing `AsRef<ChildNumber>`, such as `DerivationPath`, for instance.
-    pub fn derivePub(
-        self: ExtendedPubKey,
-        secp: secp256k1.Secp256k1,
-        path: []ChildNumber,
-    ) !ExtendedPubKey {
-        var pk = self;
-        for (path) |cnum| {
-            pk = try pk.ckdPub(secp, cnum);
-        }
-
-        return pk;
-    }
-
-    /// Compute the scalar tweak added to this key to get a child key
-    pub fn ckdPubTweak(
-        self: ExtendedPubKey,
-        i: ChildNumber,
-    ) !struct { secp256k1.SecretKey, ChainCode } {
-        switch (i) {
-            .hardened => return error.CannotDeriveFromHardenedKey,
-            .normal => |n| {
-                var hmac_engine = Hmac.init(&self.chain_code.inner);
-
-                hmac_engine.update(&self.public_key.serialize());
-
-                var buf: [4]u8 = undefined;
-                std.mem.writeInt(u32, &buf, n, .big);
-
-                hmac_engine.update(&buf);
-                var hmac_result: [Hmac.mac_length]u8 = undefined;
-                hmac_engine.final(&hmac_result);
-
-                const private_key = try secp256k1.SecretKey.fromSlice(hmac_result[0..32]);
-                const chain_code = ChainCode.fromHmac(hmac_result);
-
-                return .{ private_key, chain_code };
-            },
-        }
-    }
-
-    /// Public->Public child key derivation
-    pub fn ckdPub(
-        self: ExtendedPubKey,
-        secp: secp256k1.Secp256k1,
-        i: ChildNumber,
-    ) !ExtendedPubKey {
-        const sk, const chain_code = try self.ckdPubTweak(i);
-
-        const tweaked = try self.public_key.addExpTweak(secp, secp256k1.Scalar.fromSecretKey(sk));
-
-        return .{
-            .network = self.network,
-            .depth = self.depth + 1,
-            .parent_fingerprint = self.fingerprint(),
-            .child_number = i,
-            .public_key = tweaked,
-            .chain_code = chain_code,
-        };
-    }
-
-    /// Returns the HASH160 of the chaincode
-    pub fn identifier(self: ExtendedPubKey) XpubIdentifier {
-        return .{ .inner = hash160(&self.public_key.serialize()) };
-    }
-
-    /// Returns the first four bytes of the identifier
-    pub fn fingerprint(self: ExtendedPubKey) Fingerprint {
-        return .{ .inner = self.identifier().inner[0..4].* };
-    }
-};
-
-fn hash160(data: []const u8) [Ripemd160.digest_length]u8 {
-    var hasher256 = std.crypto.hash.sha2.Sha256.init(.{});
-    hasher256.update(data);
-
-    var out256: [std.crypto.hash.sha2.Sha256.digest_length]u8 = undefined;
-    hasher256.final(&out256);
-
-    var hasher = Ripemd160.init(.{});
-    hasher.update(&out256);
-
-    var out: [Ripemd160.digest_length]u8 = undefined;
-    hasher.final(&out);
-    return out;
-}
-
-pub const XpubIdentifier = struct {
-    inner: [Ripemd160.digest_length]u8,
-};
-
-/// A child number for a derived key
-pub const ChildNumber = union(enum) {
-    /// Non-hardened key
-    /// Key index, within [0, 2^31 - 1]
-    normal: u32,
-    /// Hardened key
-    /// Key index, within [0, 2^31 - 1]
-    hardened: u32,
-
-    pub fn fromStr(inp: []const u8) !ChildNumber {
-        const is_hardened = (inp[inp.len - 1] == '\'' or inp[inp.len - 1] == 'h');
-
-        if (is_hardened) return try fromHardenedIdx(try std.fmt.parseInt(u32, inp[0 .. inp.len - 1], 10)) else return try fromNormalIdx(try std.fmt.parseInt(u32, inp, 10));
-    }
-
-    /// Create a [`Normal`] from an index, returns an error if the index is not within
-    /// [0, 2^31 - 1].
-    ///
-    /// [`Normal`]: #variant.Normal
-    pub fn fromNormalIdx(index: u32) !ChildNumber {
-        if ((index & (1 << 31)) == 0)
-            return .{ .normal = index };
-
-        return error.InvalidChildNumber;
-    }
-
-    /// Create a [`Hardened`] from an index, returns an error if the index is not within
-    /// [0, 2^31 - 1].
-    ///
-    /// [`Hardened`]: #variant.Hardened
-    pub fn fromHardenedIdx(index: u32) !ChildNumber {
-        if (index & (1 << 31) == 0)
-            return .{ .hardened = index };
-
-        return error.InvalidChildNumber;
-    }
-
-    /// Returns `true` if the child number is a [`Normal`] value.
-    ///
-    /// [`Normal`]: #variant.Normal
-    pub fn isNormal(self: ChildNumber) bool {
-        return !self.isHardened();
-    }
-
-    /// Returns `true` if the child number is a [`Hardened`] value.
-    ///
-    /// [`Hardened`]: #variant.Hardened
-    pub fn isHardened(self: ChildNumber) bool {
-        return switch (self) {
-            .hardened => true,
-            .normal => false,
-        };
-    }
-    /// Returns the child number that is a single increment from this one.
-    pub fn increment(self: ChildNumber) !ChildNumber {
-        return switch (self) {
-            .hardened => |idx| try fromHardenedIdx(idx + 1),
-            .normal => |idx| try fromNormalIdx(idx + 1),
-        };
-    }
-
-    fn fromU32(number: u32) ChildNumber {
-        if (number & (1 << 31) != 0) {
-            return .{
-                .hardened = number ^ (1 << 31),
-            };
-        } else {
-            return .{ .normal = number };
-        }
-    }
-
-    fn toU32(self: ChildNumber) u32 {
-        return switch (self) {
-            .normal => |index| index,
-            .hardened => |index| index | (1 << 31),
-        };
-    }
-};
-
-fn testPath(
-    secp: secp256k1.Secp256k1,
-    network: Network,
-    seed: []const u8,
-    path: []ChildNumber,
-    expected_sk: []const u8,
-    expected_pk: []const u8,
-) !void {
-    var sk = try ExtendedPrivKey.initMaster(network, seed);
-    var pk = ExtendedPubKey.fromPrivateKey(secp, sk);
-
-    // Check derivation convenience method for ExtendedPrivKey
-    {
-        const actual_sk = try (try sk.derivePriv(secp, path)).toStr(std.testing.allocator);
-        defer std.testing.allocator.free(actual_sk);
-
-        try std.testing.expectEqualSlices(
-            u8,
-            actual_sk,
-            expected_sk,
-        );
-    }
-
-    // Check derivation convenience method for ExtendedPubKey, should error
-    // appropriately if any ChildNumber is hardened
-    for (path) |cnum| {
-        if (cnum.isHardened()) {
-            try std.testing.expectError(error.CannotDeriveFromHardenedKey, pk.derivePub(secp, path));
-            break;
-        }
-    } else {
-        const derivedPub = try (try pk.derivePub(secp, path)).toStr(std.testing.allocator);
-        defer std.testing.allocator.free(derivedPub);
-
-        try std.testing.expectEqualSlices(u8, derivedPub, expected_pk);
-    }
-
-    // Derive keys, checking hardened and non-hardened derivation one-by-one
-    for (path) |num| {
-        sk = try sk.ckdPriv(secp, num);
-        switch (num) {
-            .normal => {
-                const pk2 = try pk.ckdPub(secp, num);
-                pk = ExtendedPubKey.fromPrivateKey(secp, sk);
-                try std.testing.expectEqualDeep(pk, pk2);
-            },
-            .hardened => {
-                try std.testing.expectError(error.CannotDeriveFromHardenedKey, pk.ckdPub(secp, num));
-                pk = ExtendedPubKey.fromPrivateKey(secp, sk);
-            },
-        }
-    }
-    // Check result against expected base58
-    const skStr = try sk.toStr(std.testing.allocator);
-    defer std.testing.allocator.free(skStr);
-    try std.testing.expectEqualSlices(u8, skStr, expected_sk);
-
-    const pkStr = try pk.toStr(std.testing.allocator);
-    defer std.testing.allocator.free(pkStr);
-    try std.testing.expectEqualSlices(u8, pkStr, expected_pk);
-
-    // Check decoded base58 against result
-    const decoded_sk = try ExtendedPrivKey.fromStr(std.testing.allocator, expected_sk);
-    const decoded_pk = try ExtendedPubKey.fromStr(std.testing.allocator, expected_pk);
-
-    try std.testing.expectEqualDeep(decoded_sk, sk);
-    try std.testing.expectEqualDeep(decoded_pk, pk);
-}
-
-fn derivatePathFromStr(path: []const u8, allocator: std.mem.Allocator) !std.ArrayList(ChildNumber) {
-    if (path.len == 0 or (path.len == 1 and path[0] == 'm') or (path.len == 2 and path[0] == 'm' and path[1] == '/')) return std.ArrayList(ChildNumber).init(allocator);
-
-    var p = path;
-
-    if (std.mem.startsWith(u8, path, "m/")) p = path[2..];
-
-    var parts = std.mem.splitScalar(u8, p, '/');
-
-    var result = std.ArrayList(ChildNumber).init(allocator);
-    errdefer result.deinit();
-
-    while (parts.next()) |s| {
-        try result.append(try ChildNumber.fromStr(s));
-    }
-
-    return result;
-}
-
-test "schnorr_broken_privkey_ffs" {
-    // Xpriv having secret key set to all 0xFF's
-    const xpriv_str = "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fENZ3QzxW";
-    try std.testing.expectError(error.InvalidSecretKey, ExtendedPrivKey.fromStr(std.testing.allocator, xpriv_str));
-}
-
-test "vector_1" {
-    var secp = try secp256k1.Secp256k1.genNew();
-    defer secp.deinit();
-
-    var buf: [100]u8 = undefined;
-
-    const seed = try std.fmt.hexToBytes(&buf, "000102030405060708090a0b0c0d0e0f");
-    // derivation path, expected_sk , expected_pk
-    const testSuite: []const struct { Network, []const u8, []const u8, []const u8 } = &.{
-        .{
-            .MAINNET,
-            "m",
-            "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
-            "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
-        },
-        .{
-            .MAINNET,
-            "m/0h",
-            "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
-            "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
-        },
-        .{
-            .MAINNET,
-            "m/0h/1",
-            "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
-            "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
-        },
-        .{
-            .MAINNET,
-            "m/0h/1/2h",
-            "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
-            "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
-        },
-        .{
-            .MAINNET,
-            "m/0h/1/2h/2",
-            "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
-            "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
-        },
-        .{
-            .MAINNET,
-            "m/0h/1/2h/2/1000000000",
-            "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
-            "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
-        },
-    };
-
-    for (testSuite, 0..) |suite, idx| {
-        errdefer {
-            std.log.warn("suite failed n={d} : {any}", .{ idx + 1, suite });
-        }
-
-        const path = try derivatePathFromStr(suite[1], std.testing.allocator);
-        defer path.deinit();
-
-        try testPath(secp, .MAINNET, seed, path.items, suite[2], suite[3]);
-    }
-}
-
-test "vector_2" {
-    var secp = try secp256k1.Secp256k1.genNew();
-    defer secp.deinit();
-
-    var buf: [100]u8 = undefined;
-
-    const seed = try std.fmt.hexToBytes(&buf, "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542");
-    // derivation path, expected_sk , expected_pk
-    const testSuite: []const struct { Network, []const u8, []const u8, []const u8 } = &.{
-        .{
-            .MAINNET,
-            "m",
-            "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
-            "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
-        },
-        .{
-            .MAINNET,
-            "m/0",
-            "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
-            "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
-        },
-        .{
-            .MAINNET,
-            "m/0/2147483647h",
-            "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
-            "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
-        },
-        .{
-            .MAINNET,
-            "m/0/2147483647h/1",
-            "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
-            "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
-        },
-        .{
-            .MAINNET,
-            "m/0/2147483647h/1/2147483646h",
-            "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
-            "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
-        },
-        .{
-            .MAINNET,
-            "m/0/2147483647h/1/2147483646h/2",
-            "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
-            "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
-        },
-    };
-
-    for (testSuite, 0..) |suite, idx| {
-        errdefer {
-            std.log.warn("suite failed n={d} : {any}", .{ idx + 1, suite });
-        }
-
-        const path = try derivatePathFromStr(suite[1], std.testing.allocator);
-        defer path.deinit();
-
-        try testPath(secp, .MAINNET, seed, path.items, suite[2], suite[3]);
-    }
-}
-
-test "vector_3" {
-    var secp = try secp256k1.Secp256k1.genNew();
-    defer secp.deinit();
-
-    var buf: [100]u8 = undefined;
-
-    const seed = try std.fmt.hexToBytes(&buf, "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be");
-
-    const path_1 = try derivatePathFromStr("m", std.testing.allocator);
-    defer path_1.deinit();
-
-    // m
-    try testPath(secp, .MAINNET, seed, path_1.items, "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13");
-
-    // m/0h
-    const path_2 = try derivatePathFromStr("m/0h", std.testing.allocator);
-    defer path_2.deinit();
-
-    try testPath(secp, .MAINNET, seed, path_2.items, "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L", "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y");
-}
-
-test "base58_check_decode_encode" {
-    const encoded = try base58EncodeCheck(std.testing.allocator, "test");
-    defer std.testing.allocator.free(encoded);
-
-    const decoded = try base58DecodeCheck(std.testing.allocator, encoded);
-    defer std.testing.allocator.free(decoded);
-
-    try std.testing.expectEqualSlices(u8, decoded, "test");
-}
diff --git a/src/core/bip32/key.zig b/src/core/bip32/key.zig
deleted file mode 100644
index a15bb84..0000000
--- a/src/core/bip32/key.zig
+++ /dev/null
@@ -1,12 +0,0 @@
-const secp256k1 = @import("secp256k1");
-const Network = @import("bip32.zig").Network;
-
-/// A Bitcoin ECDSA private key
-pub const PrivateKey = struct {
-    /// Whether this private key should be serialized as compressed
-    compressed: bool,
-    /// The network on which this key should be used
-    network: Network,
-    /// The actual ECDSA key
-    inner: secp256k1.SecretKey,
-};
diff --git a/src/core/bip32/utils.zig b/src/core/bip32/utils.zig
deleted file mode 100644
index 4280cd0..0000000
--- a/src/core/bip32/utils.zig
+++ /dev/null
@@ -1,182 +0,0 @@
-const std = @import("std");
-const math = std.math;
-const unicode = std.unicode;
-const base58 = @import("base58");
-const Ripemd160 = @import("crypto").Ripemd160;
-
-pub const DecodedCompactSize = struct {
-    totalBytes: u8,
-    n: u64,
-};
-
-pub const EncodedCompactSize = struct {
-    compactSizeByte: u8,
-    totalBytes: u8,
-    n: u64,
-};
-
-pub fn intToHexStr(comptime T: type, data: T, buffer: []u8) !void {
-    // Number of characters to represent data in hex
-    // log16(data) + 1
-    const n: usize = if (data == 0) 1 else @intCast(math.log(T, 16, data) + 1);
-    const missing: usize = @intCast(buffer.len - n);
-    for (0..missing) |i| {
-        buffer[i] = '0';
-    }
-    _ = try std.fmt.bufPrint(buffer[missing..], "{x}", .{data});
-}
-
-pub fn toBase58(buffer: []u8, bytes: []const u8) !void {
-    const encoder = base58.Encoder.init(.{});
-    _ = try encoder.encode(bytes, buffer);
-}
-
-pub fn toBase58Allocator(allocator: std.mem.Allocator, bytes: []const u8) ![]u8 {
-    const encoder = base58.Encoder.init(.{});
-    return try encoder.encodeAlloc(allocator, bytes);
-}
-
-pub fn fromBase58(encoded: []const u8, buffer: []u8) !void {
-    const decoder = base58.Decoder.init(.{});
-    _ = try decoder.decode(encoded, buffer);
-}
-
-pub fn calculateChecksum(bytes: []const u8) [4]u8 {
-    var buffer: [32]u8 = undefined;
-    std.crypto.hash.sha2.Sha256.hash(bytes, &buffer, .{});
-    std.crypto.hash.sha2.Sha256.hash(&buffer, &buffer, .{});
-    return buffer[0..4].*;
-}
-
-pub fn verifyChecksum(bytes: []const u8, checksum: [4]u8) bool {
-    var buffer: [32]u8 = undefined;
-    std.crypto.hash.sha2.Sha256.hash(bytes, &buffer, .{});
-    std.crypto.hash.sha2.Sha256.hash(&buffer, &buffer, .{});
-
-    return std.mem.eql(u8, buffer[0..4], checksum[0..4]);
-}
-
-pub fn debugPrintBytes(comptime len: u32, bytes: []const u8) void {
-    var buf: [len]u8 = undefined;
-    _ = std.fmt.bufPrint(&buf, "{x}", .{std.fmt.fmtSliceHexLower(bytes)}) catch unreachable;
-    std.debug.print("DEBUG PRINT BYTES: {s}\n", .{buf});
-}
-
-pub fn doubleSha256(bytes: []const u8) [32]u8 {
-    var buffer: [32]u8 = undefined;
-    std.crypto.hash.sha2.Sha256.hash(bytes, &buffer, .{});
-    std.crypto.hash.sha2.Sha256.hash(&buffer, &buffer, .{});
-    return buffer;
-}
-
-pub fn hash160(bytes: []const u8) [20]u8 {
-    var hashed: [32]u8 = undefined;
-    std.crypto.hash.sha2.Sha256.hash(bytes, &hashed, .{});
-    const r = Ripemd160.hash(&hashed);
-    return r.bytes;
-}
-
-pub fn encodeutf8(in: []const u8, buffer: []u8) !u16 {
-    const v = try unicode.Utf8View.init(in);
-    var it = v.iterator();
-    var cur: u16 = 0;
-    while (it.nextCodepoint()) |codepoint| {
-        var b: [4]u8 = undefined;
-        const len: u16 = @as(u16, try unicode.utf8Encode(codepoint, &b));
-        @memcpy(buffer[cur .. cur + len], b[0..len]);
-        cur += len;
-    }
-    return cur;
-}
-
-pub fn decodeCompactSize(v: []u8) DecodedCompactSize {
-    return switch (v[0]) {
-        0...252 => DecodedCompactSize{ .totalBytes = 1, .n = v[0] },
-        253 => {
-            const n = std.mem.readInt(u16, v[1..3], .big);
-            return DecodedCompactSize{ .totalBytes = 3, .n = n };
-        },
-        254 => {
-            const n = std.mem.readInt(u32, v[1..5], .big);
-            return DecodedCompactSize{ .totalBytes = 5, .n = n };
-        },
-        255 => {
-            const n = std.mem.readInt(u64, v[1..9], .big);
-            return DecodedCompactSize{ .totalBytes = 9, .n = n };
-        },
-    };
-}
-
-pub fn encodeCompactSize(n: u64) EncodedCompactSize {
-    return switch (n) {
-        0...252 => EncodedCompactSize{ .compactSizeByte = @intCast(n), .totalBytes = 0, .n = n },
-        253...65535 => EncodedCompactSize{ .compactSizeByte = 253, .totalBytes = 2, .n = n },
-        65536...4294967295 => EncodedCompactSize{ .compactSizeByte = 254, .totalBytes = 4, .n = n },
-        4294967296...18446744073709551615 => EncodedCompactSize{ .compactSizeByte = 255, .totalBytes = 8, .n = n },
-    };
-}
-
-pub fn reverseByteOrderFromHex(comptime size: usize, hex: [size]u8) ![size]u8 {
-    var bytes: [size / 2]u8 = undefined;
-    const bytes_size = size / 2;
-    _ = try std.fmt.hexToBytes(&bytes, &hex);
-
-    for (0..bytes_size / 2) |i| { // size / 4 = bytes.len / 2
-        bytes[i] = bytes[bytes_size - 1 - i] ^ bytes[i];
-        bytes[bytes_size - 1 - i] = bytes[i] ^ bytes[bytes_size - 1 - i];
-        bytes[i] = bytes[bytes_size - 1 - i] ^ bytes[i];
-    }
-
-    var result: [size]u8 = undefined;
-    _ = try std.fmt.bufPrint(&result, "{x}", .{std.fmt.fmtSliceHexLower(&bytes)});
-    return result;
-}
-
-test "intToHexStr" {
-    var buffer: [8]u8 = undefined;
-    try intToHexStr(u8, 150, &buffer);
-    try std.testing.expectEqualSlices(u8, buffer[0..], "00000096");
-    try intToHexStr(u32, 4294967295, &buffer);
-    try std.testing.expectEqualSlices(u8, buffer[0..], "ffffffff");
-
-    var buffer2: [8]u8 = undefined;
-    try intToHexStr(u8, 0, &buffer2);
-    try std.testing.expectEqualSlices(u8, buffer2[0..], "00000000");
-}
-
-test "toBase58" {
-    const str = "00f57f296d748bb310dc0512b28231e8ebd62454557d5edaef".*;
-    var b: [25]u8 = undefined;
-    _ = try std.fmt.hexToBytes(&b, &str);
-    var base58_address: [34]u8 = undefined;
-    _ = try toBase58(&base58_address, &b);
-    try std.testing.expectEqualSlices(u8, base58_address[0..], "1PP4tMi6tep8qo8NwUDRaNw5cdiDVZYEnJ");
-}
-
-test "hash160" {
-    var str = "03525cbe17e87969013e6457c765594580dc803a8497052d7c1efb0ef401f68bd5".*;
-    var bytes: [33]u8 = undefined;
-    _ = try std.fmt.hexToBytes(&bytes, &str);
-    const r = hash160(bytes[0..]);
-    var rstr: [40]u8 = undefined;
-    _ = try std.fmt.bufPrint(&rstr, "{x}", .{std.fmt.fmtSliceHexLower(&r)});
-    try std.testing.expectEqualStrings("286fd267876fb1a24b8fe798edbc6dc6d5e2ea5b", &rstr);
-}
-
-test "reverseByteOrderFromHex" {
-    const hex1 = "7790b18693b2c4b6344577dc8d973e51388670a2b60ef1156b69f141f66b837e".*;
-    const expected1 = "7e836bf641f1696b15f10eb6a2708638513e978ddc774534b6c4b29386b19077".*;
-    const res1 = try reverseByteOrderFromHex(64, hex1);
-
-    const hex2 = "4429cda513e5258a16f5be9fe6bf9d8f18aa7d8ca6e5147b10961955db88ac74".*;
-    const expected2 = "74ac88db551996107b14e5a68c7daa188f9dbfe69fbef5168a25e513a5cd2944".*;
-    const res2 = try reverseByteOrderFromHex(64, hex2);
-
-    const hex3 = "396b7f0fcac84f700b471fc72874f56795433b7cb7657fe3ff9e9d0e573960a7".*;
-    const expected3 = "a76039570e9d9effe37f65b77c3b439567f57428c71f470b704fc8ca0f7f6b39".*;
-    const res3 = try reverseByteOrderFromHex(64, hex3);
-
-    try std.testing.expectEqualStrings(&expected1, &res1);
-    try std.testing.expectEqualStrings(&expected2, &res2);
-    try std.testing.expectEqualStrings(&expected3, &res3);
-}
diff --git a/src/core/bip39/bip39.zig b/src/core/bip39/bip39.zig
deleted file mode 100644
index 005e4f7..0000000
--- a/src/core/bip39/bip39.zig
+++ /dev/null
@@ -1,352 +0,0 @@
-//! # BIP39 Mnemonic Codes
-//!
-//! https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
-//!
-const std = @import("std");
-const language = @import("language.zig");
-const pbkdf2 = @import("pbkdf2.zig");
-
-/// The minimum number of words in a mnemonic.
-const MIN_NB_WORDS: usize = 12;
-
-/// The maximum number of words in a mnemonic.
-const MAX_NB_WORDS: usize = 24;
-
-/// The index used to indicate the mnemonic ended.
-const EOF: u16 = std.math.maxInt(u16);
-
-/// A mnemonic code.
-///
-/// The [core::str::FromStr] implementation will try to determine the language of the
-/// mnemonic from all the supported languages. (Languages have to be explicitly enabled using
-/// the Cargo features.)
-///
-/// Supported number of words are 12, 15, 18, 21, and 24.
-pub const Mnemonic = struct {
-    /// The language the mnemonic.
-    lang: language.Language,
-    /// The indiced of the words.
-    /// Mnemonics with less than the max nb of words are terminated with EOF.
-    words: [MAX_NB_WORDS]u16,
-
-    /// Parse a mnemonic in normalized UTF8 in the given language.
-    pub fn parseInNormalized(lang: language.Language, s: []const u8) !Mnemonic {
-        var it = std.mem.splitScalar(u8, s, ' ');
-        var nb_words: usize = 0;
-
-        while (it.next()) |_| nb_words += 1;
-        it.reset();
-
-        if (isInvalidWordCount(nb_words)) {
-            return error.BadWordCount;
-        }
-
-        // Here we will store the eventual words.
-        var words = [_]u16{EOF} ** MAX_NB_WORDS;
-
-        // And here we keep track of the bits to calculate and validate the checksum.
-        // We only use `nb_words * 11` elements in this array.
-        var bits = [_]bool{false} ** (MAX_NB_WORDS * 11);
-
-        {
-            var i: usize = 0;
-            while (it.next()) |word| {
-                const idx = lang.findWord(word) orelse return error.UnknownWord;
-
-                words[i] = idx;
-
-                for (0..11) |j| {
-                    bits[i * 11 + j] = std.math.shr(u16, idx, 10 - j) & 1 == 1;
-                }
-                i += 1;
-            }
-        }
-
-        // Verify the checksum.
-        // We only use `nb_words / 3 * 4` elements in this array.
-
-        var entropy = [_]u8{0} ** (MAX_NB_WORDS / 3 * 4);
-        const nb_bytes_entropy = nb_words / 3 * 4;
-        for (0..nb_bytes_entropy) |i| {
-            for (0..8) |j| {
-                if (bits[i * 8 + j]) {
-                    entropy[i] += std.math.shl(u8, 1, 7 - j);
-                }
-            }
-        }
-
-        var hasher = std.crypto.hash.sha2.Sha256.init(.{});
-        hasher.update(entropy[0..nb_bytes_entropy]);
-
-        const check = hasher.finalResult();
-
-        for (0..nb_bytes_entropy / 4) |i| {
-            if (bits[8 * nb_bytes_entropy + i] != ((check[i / 8] & (std.math.shl(usize, 1, 7 - (i % 8)))) > 0)) {
-                return error.InvalidChecksum;
-            }
-        }
-
-        return .{
-            .lang = lang,
-            .words = words,
-        };
-    }
-
-    /// Convert to seed bytes with a passphrase in normalized UTF8.
-    pub fn toSeedNormalized(self: Mnemonic, normalized_passphrase: []const u8) ![64]u8 {
-        const PBKDF2_ROUNDS: usize = 2048;
-        const PBKDF2_BYTES: usize = 64;
-
-        var seed = [_]u8{0} ** PBKDF2_BYTES;
-
-        pbkdf2.pbkdf2((try self.getWords()).slice(), normalized_passphrase, PBKDF2_ROUNDS, &seed);
-        return seed;
-    }
-
-    /// Returns an slice over [Mnemonic] word indices.
-    ///
-    pub fn wordIndices(self: Mnemonic) !std.BoundedArray(u16, MAX_NB_WORDS) {
-        var result = try std.BoundedArray(u16, MAX_NB_WORDS).init(0);
-
-        for (self.words) |w| {
-            if (w != EOF) {
-                result.appendAssumeCapacity(w);
-                continue;
-            }
-
-            break;
-        }
-
-        return result;
-    }
-
-    /// Returns an iterator over the words of the [Mnemonic].
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// const bip39 = @import("bip39");
-    ///
-    /// const mnemonic = try bip39.Mnemonic.fromEntropy(&([_]u8{0} ** 32));
-    /// for (mnemonic.words()) |word| {
-    ///     std.log.debug("word: {s}", .{word});
-    /// }
-    /// ```
-    pub fn getWords(self: Mnemonic) !std.BoundedArray([]const u8, MAX_NB_WORDS) {
-        const list = self.lang.wordList();
-        const word_indices = try self.wordIndices();
-
-        var result = try std.BoundedArray([]const u8, MAX_NB_WORDS).init(0);
-
-        for (word_indices.slice()) |i| {
-            result.appendAssumeCapacity(list[i]);
-        }
-
-        return result;
-    }
-
-    /// Create a new [Mnemonic] in the specified language from the given entropy.
-    /// Entropy must be a multiple of 32 bits (4 bytes) and 128-256 bits in length.
-    pub fn fromEntropyIn(lang: language.Language, entropy: []const u8) !Mnemonic {
-        const MAX_ENTROPY_BITS: usize = 256;
-        const MIN_ENTROPY_BITS: usize = 128;
-        const MAX_CHECKSUM_BITS: usize = 8;
-
-        const nb_bytes = entropy.len;
-        const nb_bits = nb_bytes * 8;
-
-        if (nb_bits % 32 != 0) {
-            return error.BadEntropyBitCount;
-        }
-
-        if (nb_bits < MIN_ENTROPY_BITS or nb_bits > MAX_ENTROPY_BITS) {
-            return error.BadEntropyBitCount;
-        }
-
-        const check = v: {
-            var out: [std.crypto.hash.sha2.Sha256.digest_length]u8 = undefined;
-            std.crypto.hash.sha2.Sha256.hash(entropy, &out, .{});
-            break :v out;
-        };
-
-        var bits = [_]bool{false} ** (MAX_ENTROPY_BITS + MAX_CHECKSUM_BITS);
-
-        for (0..nb_bytes) |i| {
-            for (0..8) |j| {
-                bits[i * 8 + j] = (entropy[i] & (std.math.shl(usize, 1, 7 - j))) > 0;
-            }
-        }
-
-        for (0..nb_bytes / 4) |i| {
-            bits[8 * nb_bytes + i] = (check[i / 8] & (std.math.shl(usize, 1, 7 - (i % 8)))) > 0;
-        }
-
-        var words = [_]u16{EOF} ** MAX_NB_WORDS;
-        const nb_words = nb_bytes * 3 / 4;
-        for (0..nb_words) |i| {
-            var idx: u16 = 0;
-            for (0..11) |j| {
-                if (bits[i * 11 + j]) {
-                    idx += std.math.shl(u16, 1, @as(u16, @truncate(10 - j)));
-                }
-            }
-
-            words[i] = idx;
-        }
-
-        return .{
-            .lang = lang,
-            .words = words,
-        };
-    }
-};
-
-fn isInvalidWordCount(word_count: usize) bool {
-    return word_count < MIN_NB_WORDS or word_count % 3 != 0 or word_count > MAX_NB_WORDS;
-}
-
-test "english_vectors" {
-    // These vectors are tuples of
-    // (entropy, mnemonic, seed)
-
-    const test_vectors = [_]struct { []const u8, []const u8, []const u8 }{
-        .{
-            "00000000000000000000000000000000",
-            "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
-            "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04",
-        },
-        .{
-            "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
-            "legal winner thank year wave sausage worth useful legal winner thank yellow",
-            "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607",
-        },
-        .{
-            "80808080808080808080808080808080",
-            "letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
-            "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8",
-        },
-        .{
-            "ffffffffffffffffffffffffffffffff",
-            "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
-            "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069",
-        },
-        .{
-            "000000000000000000000000000000000000000000000000",
-            "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
-            "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa",
-        },
-        .{
-            "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
-            "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
-            "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd",
-        },
-        .{
-            "808080808080808080808080808080808080808080808080",
-            "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
-            "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65",
-        },
-        .{
-            "ffffffffffffffffffffffffffffffffffffffffffffffff",
-            "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
-            "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528",
-        },
-        .{
-            "0000000000000000000000000000000000000000000000000000000000000000",
-            "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
-            "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8",
-        },
-        .{
-            "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
-            "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title",
-            "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87",
-        },
-        .{
-            "8080808080808080808080808080808080808080808080808080808080808080",
-            "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless",
-            "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f",
-        },
-        .{
-            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-            "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote",
-            "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad",
-        },
-        .{
-            "9e885d952ad362caeb4efe34a8e91bd2",
-            "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic",
-            "274ddc525802f7c828d8ef7ddbcdc5304e87ac3535913611fbbfa986d0c9e5476c91689f9c8a54fd55bd38606aa6a8595ad213d4c9c9f9aca3fb217069a41028",
-        },
-        .{
-            "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b",
-            "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog",
-            "628c3827a8823298ee685db84f55caa34b5cc195a778e52d45f59bcf75aba68e4d7590e101dc414bc1bbd5737666fbbef35d1f1903953b66624f910feef245ac",
-        },
-        .{
-            "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c",
-            "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length",
-            "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440",
-        },
-        .{
-            "c0ba5a8e914111210f2bd131f3d5e08d",
-            "scheme spot photo card baby mountain device kick cradle pact join borrow",
-            "ea725895aaae8d4c1cf682c1bfd2d358d52ed9f0f0591131b559e2724bb234fca05aa9c02c57407e04ee9dc3b454aa63fbff483a8b11de949624b9f1831a9612",
-        },
-        .{
-            "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3",
-            "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave",
-            "fd579828af3da1d32544ce4db5c73d53fc8acc4ddb1e3b251a31179cdb71e853c56d2fcb11aed39898ce6c34b10b5382772db8796e52837b54468aeb312cfc3d",
-        },
-        .{
-            "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863",
-            "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside",
-            "72be8e052fc4919d2adf28d5306b5474b0069df35b02303de8c1729c9538dbb6fc2d731d5f832193cd9fb6aeecbc469594a70e3dd50811b5067f3b88b28c3e8d",
-        },
-        .{
-            "23db8160a31d3e0dca3688ed941adbf3",
-            "cat swing flag economy stadium alone churn speed unique patch report train",
-            "deb5f45449e615feff5640f2e49f933ff51895de3b4381832b3139941c57b59205a42480c52175b6efcffaa58a2503887c1e8b363a707256bdd2b587b46541f5",
-        },
-        .{
-            "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0",
-            "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access",
-            "4cbdff1ca2db800fd61cae72a57475fdc6bab03e441fd63f96dabd1f183ef5b782925f00105f318309a7e9c3ea6967c7801e46c8a58082674c860a37b93eda02",
-        },
-        .{
-            "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad",
-            "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform",
-            "26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d",
-        },
-        .{
-            "f30f8c1da665478f49b001d94c5fc452",
-            "vessel ladder alter error federal sibling chat ability sun glass valve picture",
-            "2aaa9242daafcee6aa9d7269f17d4efe271e1b9a529178d7dc139cd18747090bf9d60295d0ce74309a78852a9caadf0af48aae1c6253839624076224374bc63f",
-        },
-        .{
-            "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05",
-            "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump",
-            "7b4a10be9d98e6cba265566db7f136718e1398c71cb581e1b2f464cac1ceedf4f3e274dc270003c670ad8d02c4558b2f8e39edea2775c9e232c7cb798b069e88",
-        },
-        .{
-            "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f",
-            "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold",
-            "01f5bced59dec48e362f2c45b5de68b9fd6c92c6634f44d6d40aab69056506f0e35524a518034ddc1192e1dacd32c1ed3eaa3c3b131c88ed8e7e54c49a5d0998",
-        },
-    };
-
-    var buf: [300]u8 = undefined;
-
-    for (test_vectors) |vector| {
-        const entropy = try std.fmt.hexToBytes(&buf, vector[0]);
-        const mn = try Mnemonic.fromEntropyIn(.english, entropy);
-        const mn1 = try Mnemonic.parseInNormalized(.english, vector[1]);
-
-        try std.testing.expectEqualDeep(mn, mn1);
-
-        const seed = try std.fmt.hexToBytes(buf[100..], vector[2]);
-
-        const seeded = try mn.toSeedNormalized("TREZOR");
-
-        try std.testing.expectEqualSlices(u8, &seeded, seed);
-    }
-}
diff --git a/src/core/bip39/language.zig b/src/core/bip39/language.zig
deleted file mode 100644
index 22ac827..0000000
--- a/src/core/bip39/language.zig
+++ /dev/null
@@ -1,2124 +0,0 @@
-const std = @import("std");
-
-/// The maximum number of languages enabled.
-pub const MAX_NB_LANGUAGES: usize = 9;
-
-pub const Language = enum {
-    /// The English language.
-    english,
-
-    pub inline fn wordList(self: Language) *const [2048][]const u8 {
-        return switch (self) {
-            inline .english => return &ENGLISH_WORDS,
-        };
-    }
-
-    /// Returns true if all words in the list are guaranteed to
-    /// only be in this list and not in any other.
-    pub inline fn uniqueWords(self: Language) bool {
-        return switch (self) {
-            inline .english => false,
-        };
-    }
-
-    /// Get words from the word list that start with the given prefix.
-    pub fn wordsByPrefix(self: Language, prefix: []const u8) ?[]const []const u8 {
-        // The words in the word list are ordered lexicographically. This means
-        // that we cannot use `binary_search` to find words more efficiently,
-        // because the Rust ordering is based on the byte values. However, it
-        // does mean that words that share a prefix will follow each other.
-        var start_from: usize = 0;
-        var count: usize = 0;
-
-        const word_list = self.wordList();
-        for (word_list.*, 0..) |w, idx| {
-            if (std.mem.startsWith(u8, w, prefix)) {
-                count = 1;
-                start_from = idx;
-
-                for (idx + 1..2048) |i| {
-                    if (!std.mem.startsWith(u8, word_list.*[i], prefix)) break;
-
-                    count += 1;
-                }
-                break;
-            }
-        }
-
-        if (count == 0) return null;
-
-        return word_list[start_from .. start_from + count];
-    }
-
-    /// Get the index of the word in the word list.
-    pub inline fn findWord(self: Language, word: []const u8) ?u16 {
-        for (self.wordList(), 0..) |w, i| {
-            if (std.mem.eql(u8, w, word)) return @truncate(i);
-        }
-
-        return null;
-    }
-};
-
-const ENGLISH_WORDS: [2048][]const u8 = .{
-    "abandon",
-    "ability",
-    "able",
-    "about",
-    "above",
-    "absent",
-    "absorb",
-    "abstract",
-    "absurd",
-    "abuse",
-    "access",
-    "accident",
-    "account",
-    "accuse",
-    "achieve",
-    "acid",
-    "acoustic",
-    "acquire",
-    "across",
-    "act",
-    "action",
-    "actor",
-    "actress",
-    "actual",
-    "adapt",
-    "add",
-    "addict",
-    "address",
-    "adjust",
-    "admit",
-    "adult",
-    "advance",
-    "advice",
-    "aerobic",
-    "affair",
-    "afford",
-    "afraid",
-    "again",
-    "age",
-    "agent",
-    "agree",
-    "ahead",
-    "aim",
-    "air",
-    "airport",
-    "aisle",
-    "alarm",
-    "album",
-    "alcohol",
-    "alert",
-    "alien",
-    "all",
-    "alley",
-    "allow",
-    "almost",
-    "alone",
-    "alpha",
-    "already",
-    "also",
-    "alter",
-    "always",
-    "amateur",
-    "amazing",
-    "among",
-    "amount",
-    "amused",
-    "analyst",
-    "anchor",
-    "ancient",
-    "anger",
-    "angle",
-    "angry",
-    "animal",
-    "ankle",
-    "announce",
-    "annual",
-    "another",
-    "answer",
-    "antenna",
-    "antique",
-    "anxiety",
-    "any",
-    "apart",
-    "apology",
-    "appear",
-    "apple",
-    "approve",
-    "april",
-    "arch",
-    "arctic",
-    "area",
-    "arena",
-    "argue",
-    "arm",
-    "armed",
-    "armor",
-    "army",
-    "around",
-    "arrange",
-    "arrest",
-    "arrive",
-    "arrow",
-    "art",
-    "artefact",
-    "artist",
-    "artwork",
-    "ask",
-    "aspect",
-    "assault",
-    "asset",
-    "assist",
-    "assume",
-    "asthma",
-    "athlete",
-    "atom",
-    "attack",
-    "attend",
-    "attitude",
-    "attract",
-    "auction",
-    "audit",
-    "august",
-    "aunt",
-    "author",
-    "auto",
-    "autumn",
-    "average",
-    "avocado",
-    "avoid",
-    "awake",
-    "aware",
-    "away",
-    "awesome",
-    "awful",
-    "awkward",
-    "axis",
-    "baby",
-    "bachelor",
-    "bacon",
-    "badge",
-    "bag",
-    "balance",
-    "balcony",
-    "ball",
-    "bamboo",
-    "banana",
-    "banner",
-    "bar",
-    "barely",
-    "bargain",
-    "barrel",
-    "base",
-    "basic",
-    "basket",
-    "battle",
-    "beach",
-    "bean",
-    "beauty",
-    "because",
-    "become",
-    "beef",
-    "before",
-    "begin",
-    "behave",
-    "behind",
-    "believe",
-    "below",
-    "belt",
-    "bench",
-    "benefit",
-    "best",
-    "betray",
-    "better",
-    "between",
-    "beyond",
-    "bicycle",
-    "bid",
-    "bike",
-    "bind",
-    "biology",
-    "bird",
-    "birth",
-    "bitter",
-    "black",
-    "blade",
-    "blame",
-    "blanket",
-    "blast",
-    "bleak",
-    "bless",
-    "blind",
-    "blood",
-    "blossom",
-    "blouse",
-    "blue",
-    "blur",
-    "blush",
-    "board",
-    "boat",
-    "body",
-    "boil",
-    "bomb",
-    "bone",
-    "bonus",
-    "book",
-    "boost",
-    "border",
-    "boring",
-    "borrow",
-    "boss",
-    "bottom",
-    "bounce",
-    "box",
-    "boy",
-    "bracket",
-    "brain",
-    "brand",
-    "brass",
-    "brave",
-    "bread",
-    "breeze",
-    "brick",
-    "bridge",
-    "brief",
-    "bright",
-    "bring",
-    "brisk",
-    "broccoli",
-    "broken",
-    "bronze",
-    "broom",
-    "brother",
-    "brown",
-    "brush",
-    "bubble",
-    "buddy",
-    "budget",
-    "buffalo",
-    "build",
-    "bulb",
-    "bulk",
-    "bullet",
-    "bundle",
-    "bunker",
-    "burden",
-    "burger",
-    "burst",
-    "bus",
-    "business",
-    "busy",
-    "butter",
-    "buyer",
-    "buzz",
-    "cabbage",
-    "cabin",
-    "cable",
-    "cactus",
-    "cage",
-    "cake",
-    "call",
-    "calm",
-    "camera",
-    "camp",
-    "can",
-    "canal",
-    "cancel",
-    "candy",
-    "cannon",
-    "canoe",
-    "canvas",
-    "canyon",
-    "capable",
-    "capital",
-    "captain",
-    "car",
-    "carbon",
-    "card",
-    "cargo",
-    "carpet",
-    "carry",
-    "cart",
-    "case",
-    "cash",
-    "casino",
-    "castle",
-    "casual",
-    "cat",
-    "catalog",
-    "catch",
-    "category",
-    "cattle",
-    "caught",
-    "cause",
-    "caution",
-    "cave",
-    "ceiling",
-    "celery",
-    "cement",
-    "census",
-    "century",
-    "cereal",
-    "certain",
-    "chair",
-    "chalk",
-    "champion",
-    "change",
-    "chaos",
-    "chapter",
-    "charge",
-    "chase",
-    "chat",
-    "cheap",
-    "check",
-    "cheese",
-    "chef",
-    "cherry",
-    "chest",
-    "chicken",
-    "chief",
-    "child",
-    "chimney",
-    "choice",
-    "choose",
-    "chronic",
-    "chuckle",
-    "chunk",
-    "churn",
-    "cigar",
-    "cinnamon",
-    "circle",
-    "citizen",
-    "city",
-    "civil",
-    "claim",
-    "clap",
-    "clarify",
-    "claw",
-    "clay",
-    "clean",
-    "clerk",
-    "clever",
-    "click",
-    "client",
-    "cliff",
-    "climb",
-    "clinic",
-    "clip",
-    "clock",
-    "clog",
-    "close",
-    "cloth",
-    "cloud",
-    "clown",
-    "club",
-    "clump",
-    "cluster",
-    "clutch",
-    "coach",
-    "coast",
-    "coconut",
-    "code",
-    "coffee",
-    "coil",
-    "coin",
-    "collect",
-    "color",
-    "column",
-    "combine",
-    "come",
-    "comfort",
-    "comic",
-    "common",
-    "company",
-    "concert",
-    "conduct",
-    "confirm",
-    "congress",
-    "connect",
-    "consider",
-    "control",
-    "convince",
-    "cook",
-    "cool",
-    "copper",
-    "copy",
-    "coral",
-    "core",
-    "corn",
-    "correct",
-    "cost",
-    "cotton",
-    "couch",
-    "country",
-    "couple",
-    "course",
-    "cousin",
-    "cover",
-    "coyote",
-    "crack",
-    "cradle",
-    "craft",
-    "cram",
-    "crane",
-    "crash",
-    "crater",
-    "crawl",
-    "crazy",
-    "cream",
-    "credit",
-    "creek",
-    "crew",
-    "cricket",
-    "crime",
-    "crisp",
-    "critic",
-    "crop",
-    "cross",
-    "crouch",
-    "crowd",
-    "crucial",
-    "cruel",
-    "cruise",
-    "crumble",
-    "crunch",
-    "crush",
-    "cry",
-    "crystal",
-    "cube",
-    "culture",
-    "cup",
-    "cupboard",
-    "curious",
-    "current",
-    "curtain",
-    "curve",
-    "cushion",
-    "custom",
-    "cute",
-    "cycle",
-    "dad",
-    "damage",
-    "damp",
-    "dance",
-    "danger",
-    "daring",
-    "dash",
-    "daughter",
-    "dawn",
-    "day",
-    "deal",
-    "debate",
-    "debris",
-    "decade",
-    "december",
-    "decide",
-    "decline",
-    "decorate",
-    "decrease",
-    "deer",
-    "defense",
-    "define",
-    "defy",
-    "degree",
-    "delay",
-    "deliver",
-    "demand",
-    "demise",
-    "denial",
-    "dentist",
-    "deny",
-    "depart",
-    "depend",
-    "deposit",
-    "depth",
-    "deputy",
-    "derive",
-    "describe",
-    "desert",
-    "design",
-    "desk",
-    "despair",
-    "destroy",
-    "detail",
-    "detect",
-    "develop",
-    "device",
-    "devote",
-    "diagram",
-    "dial",
-    "diamond",
-    "diary",
-    "dice",
-    "diesel",
-    "diet",
-    "differ",
-    "digital",
-    "dignity",
-    "dilemma",
-    "dinner",
-    "dinosaur",
-    "direct",
-    "dirt",
-    "disagree",
-    "discover",
-    "disease",
-    "dish",
-    "dismiss",
-    "disorder",
-    "display",
-    "distance",
-    "divert",
-    "divide",
-    "divorce",
-    "dizzy",
-    "doctor",
-    "document",
-    "dog",
-    "doll",
-    "dolphin",
-    "domain",
-    "donate",
-    "donkey",
-    "donor",
-    "door",
-    "dose",
-    "double",
-    "dove",
-    "draft",
-    "dragon",
-    "drama",
-    "drastic",
-    "draw",
-    "dream",
-    "dress",
-    "drift",
-    "drill",
-    "drink",
-    "drip",
-    "drive",
-    "drop",
-    "drum",
-    "dry",
-    "duck",
-    "dumb",
-    "dune",
-    "during",
-    "dust",
-    "dutch",
-    "duty",
-    "dwarf",
-    "dynamic",
-    "eager",
-    "eagle",
-    "early",
-    "earn",
-    "earth",
-    "easily",
-    "east",
-    "easy",
-    "echo",
-    "ecology",
-    "economy",
-    "edge",
-    "edit",
-    "educate",
-    "effort",
-    "egg",
-    "eight",
-    "either",
-    "elbow",
-    "elder",
-    "electric",
-    "elegant",
-    "element",
-    "elephant",
-    "elevator",
-    "elite",
-    "else",
-    "embark",
-    "embody",
-    "embrace",
-    "emerge",
-    "emotion",
-    "employ",
-    "empower",
-    "empty",
-    "enable",
-    "enact",
-    "end",
-    "endless",
-    "endorse",
-    "enemy",
-    "energy",
-    "enforce",
-    "engage",
-    "engine",
-    "enhance",
-    "enjoy",
-    "enlist",
-    "enough",
-    "enrich",
-    "enroll",
-    "ensure",
-    "enter",
-    "entire",
-    "entry",
-    "envelope",
-    "episode",
-    "equal",
-    "equip",
-    "era",
-    "erase",
-    "erode",
-    "erosion",
-    "error",
-    "erupt",
-    "escape",
-    "essay",
-    "essence",
-    "estate",
-    "eternal",
-    "ethics",
-    "evidence",
-    "evil",
-    "evoke",
-    "evolve",
-    "exact",
-    "example",
-    "excess",
-    "exchange",
-    "excite",
-    "exclude",
-    "excuse",
-    "execute",
-    "exercise",
-    "exhaust",
-    "exhibit",
-    "exile",
-    "exist",
-    "exit",
-    "exotic",
-    "expand",
-    "expect",
-    "expire",
-    "explain",
-    "expose",
-    "express",
-    "extend",
-    "extra",
-    "eye",
-    "eyebrow",
-    "fabric",
-    "face",
-    "faculty",
-    "fade",
-    "faint",
-    "faith",
-    "fall",
-    "false",
-    "fame",
-    "family",
-    "famous",
-    "fan",
-    "fancy",
-    "fantasy",
-    "farm",
-    "fashion",
-    "fat",
-    "fatal",
-    "father",
-    "fatigue",
-    "fault",
-    "favorite",
-    "feature",
-    "february",
-    "federal",
-    "fee",
-    "feed",
-    "feel",
-    "female",
-    "fence",
-    "festival",
-    "fetch",
-    "fever",
-    "few",
-    "fiber",
-    "fiction",
-    "field",
-    "figure",
-    "file",
-    "film",
-    "filter",
-    "final",
-    "find",
-    "fine",
-    "finger",
-    "finish",
-    "fire",
-    "firm",
-    "first",
-    "fiscal",
-    "fish",
-    "fit",
-    "fitness",
-    "fix",
-    "flag",
-    "flame",
-    "flash",
-    "flat",
-    "flavor",
-    "flee",
-    "flight",
-    "flip",
-    "float",
-    "flock",
-    "floor",
-    "flower",
-    "fluid",
-    "flush",
-    "fly",
-    "foam",
-    "focus",
-    "fog",
-    "foil",
-    "fold",
-    "follow",
-    "food",
-    "foot",
-    "force",
-    "forest",
-    "forget",
-    "fork",
-    "fortune",
-    "forum",
-    "forward",
-    "fossil",
-    "foster",
-    "found",
-    "fox",
-    "fragile",
-    "frame",
-    "frequent",
-    "fresh",
-    "friend",
-    "fringe",
-    "frog",
-    "front",
-    "frost",
-    "frown",
-    "frozen",
-    "fruit",
-    "fuel",
-    "fun",
-    "funny",
-    "furnace",
-    "fury",
-    "future",
-    "gadget",
-    "gain",
-    "galaxy",
-    "gallery",
-    "game",
-    "gap",
-    "garage",
-    "garbage",
-    "garden",
-    "garlic",
-    "garment",
-    "gas",
-    "gasp",
-    "gate",
-    "gather",
-    "gauge",
-    "gaze",
-    "general",
-    "genius",
-    "genre",
-    "gentle",
-    "genuine",
-    "gesture",
-    "ghost",
-    "giant",
-    "gift",
-    "giggle",
-    "ginger",
-    "giraffe",
-    "girl",
-    "give",
-    "glad",
-    "glance",
-    "glare",
-    "glass",
-    "glide",
-    "glimpse",
-    "globe",
-    "gloom",
-    "glory",
-    "glove",
-    "glow",
-    "glue",
-    "goat",
-    "goddess",
-    "gold",
-    "good",
-    "goose",
-    "gorilla",
-    "gospel",
-    "gossip",
-    "govern",
-    "gown",
-    "grab",
-    "grace",
-    "grain",
-    "grant",
-    "grape",
-    "grass",
-    "gravity",
-    "great",
-    "green",
-    "grid",
-    "grief",
-    "grit",
-    "grocery",
-    "group",
-    "grow",
-    "grunt",
-    "guard",
-    "guess",
-    "guide",
-    "guilt",
-    "guitar",
-    "gun",
-    "gym",
-    "habit",
-    "hair",
-    "half",
-    "hammer",
-    "hamster",
-    "hand",
-    "happy",
-    "harbor",
-    "hard",
-    "harsh",
-    "harvest",
-    "hat",
-    "have",
-    "hawk",
-    "hazard",
-    "head",
-    "health",
-    "heart",
-    "heavy",
-    "hedgehog",
-    "height",
-    "hello",
-    "helmet",
-    "help",
-    "hen",
-    "hero",
-    "hidden",
-    "high",
-    "hill",
-    "hint",
-    "hip",
-    "hire",
-    "history",
-    "hobby",
-    "hockey",
-    "hold",
-    "hole",
-    "holiday",
-    "hollow",
-    "home",
-    "honey",
-    "hood",
-    "hope",
-    "horn",
-    "horror",
-    "horse",
-    "hospital",
-    "host",
-    "hotel",
-    "hour",
-    "hover",
-    "hub",
-    "huge",
-    "human",
-    "humble",
-    "humor",
-    "hundred",
-    "hungry",
-    "hunt",
-    "hurdle",
-    "hurry",
-    "hurt",
-    "husband",
-    "hybrid",
-    "ice",
-    "icon",
-    "idea",
-    "identify",
-    "idle",
-    "ignore",
-    "ill",
-    "illegal",
-    "illness",
-    "image",
-    "imitate",
-    "immense",
-    "immune",
-    "impact",
-    "impose",
-    "improve",
-    "impulse",
-    "inch",
-    "include",
-    "income",
-    "increase",
-    "index",
-    "indicate",
-    "indoor",
-    "industry",
-    "infant",
-    "inflict",
-    "inform",
-    "inhale",
-    "inherit",
-    "initial",
-    "inject",
-    "injury",
-    "inmate",
-    "inner",
-    "innocent",
-    "input",
-    "inquiry",
-    "insane",
-    "insect",
-    "inside",
-    "inspire",
-    "install",
-    "intact",
-    "interest",
-    "into",
-    "invest",
-    "invite",
-    "involve",
-    "iron",
-    "island",
-    "isolate",
-    "issue",
-    "item",
-    "ivory",
-    "jacket",
-    "jaguar",
-    "jar",
-    "jazz",
-    "jealous",
-    "jeans",
-    "jelly",
-    "jewel",
-    "job",
-    "join",
-    "joke",
-    "journey",
-    "joy",
-    "judge",
-    "juice",
-    "jump",
-    "jungle",
-    "junior",
-    "junk",
-    "just",
-    "kangaroo",
-    "keen",
-    "keep",
-    "ketchup",
-    "key",
-    "kick",
-    "kid",
-    "kidney",
-    "kind",
-    "kingdom",
-    "kiss",
-    "kit",
-    "kitchen",
-    "kite",
-    "kitten",
-    "kiwi",
-    "knee",
-    "knife",
-    "knock",
-    "know",
-    "lab",
-    "label",
-    "labor",
-    "ladder",
-    "lady",
-    "lake",
-    "lamp",
-    "language",
-    "laptop",
-    "large",
-    "later",
-    "latin",
-    "laugh",
-    "laundry",
-    "lava",
-    "law",
-    "lawn",
-    "lawsuit",
-    "layer",
-    "lazy",
-    "leader",
-    "leaf",
-    "learn",
-    "leave",
-    "lecture",
-    "left",
-    "leg",
-    "legal",
-    "legend",
-    "leisure",
-    "lemon",
-    "lend",
-    "length",
-    "lens",
-    "leopard",
-    "lesson",
-    "letter",
-    "level",
-    "liar",
-    "liberty",
-    "library",
-    "license",
-    "life",
-    "lift",
-    "light",
-    "like",
-    "limb",
-    "limit",
-    "link",
-    "lion",
-    "liquid",
-    "list",
-    "little",
-    "live",
-    "lizard",
-    "load",
-    "loan",
-    "lobster",
-    "local",
-    "lock",
-    "logic",
-    "lonely",
-    "long",
-    "loop",
-    "lottery",
-    "loud",
-    "lounge",
-    "love",
-    "loyal",
-    "lucky",
-    "luggage",
-    "lumber",
-    "lunar",
-    "lunch",
-    "luxury",
-    "lyrics",
-    "machine",
-    "mad",
-    "magic",
-    "magnet",
-    "maid",
-    "mail",
-    "main",
-    "major",
-    "make",
-    "mammal",
-    "man",
-    "manage",
-    "mandate",
-    "mango",
-    "mansion",
-    "manual",
-    "maple",
-    "marble",
-    "march",
-    "margin",
-    "marine",
-    "market",
-    "marriage",
-    "mask",
-    "mass",
-    "master",
-    "match",
-    "material",
-    "math",
-    "matrix",
-    "matter",
-    "maximum",
-    "maze",
-    "meadow",
-    "mean",
-    "measure",
-    "meat",
-    "mechanic",
-    "medal",
-    "media",
-    "melody",
-    "melt",
-    "member",
-    "memory",
-    "mention",
-    "menu",
-    "mercy",
-    "merge",
-    "merit",
-    "merry",
-    "mesh",
-    "message",
-    "metal",
-    "method",
-    "middle",
-    "midnight",
-    "milk",
-    "million",
-    "mimic",
-    "mind",
-    "minimum",
-    "minor",
-    "minute",
-    "miracle",
-    "mirror",
-    "misery",
-    "miss",
-    "mistake",
-    "mix",
-    "mixed",
-    "mixture",
-    "mobile",
-    "model",
-    "modify",
-    "mom",
-    "moment",
-    "monitor",
-    "monkey",
-    "monster",
-    "month",
-    "moon",
-    "moral",
-    "more",
-    "morning",
-    "mosquito",
-    "mother",
-    "motion",
-    "motor",
-    "mountain",
-    "mouse",
-    "move",
-    "movie",
-    "much",
-    "muffin",
-    "mule",
-    "multiply",
-    "muscle",
-    "museum",
-    "mushroom",
-    "music",
-    "must",
-    "mutual",
-    "myself",
-    "mystery",
-    "myth",
-    "naive",
-    "name",
-    "napkin",
-    "narrow",
-    "nasty",
-    "nation",
-    "nature",
-    "near",
-    "neck",
-    "need",
-    "negative",
-    "neglect",
-    "neither",
-    "nephew",
-    "nerve",
-    "nest",
-    "net",
-    "network",
-    "neutral",
-    "never",
-    "news",
-    "next",
-    "nice",
-    "night",
-    "noble",
-    "noise",
-    "nominee",
-    "noodle",
-    "normal",
-    "north",
-    "nose",
-    "notable",
-    "note",
-    "nothing",
-    "notice",
-    "novel",
-    "now",
-    "nuclear",
-    "number",
-    "nurse",
-    "nut",
-    "oak",
-    "obey",
-    "object",
-    "oblige",
-    "obscure",
-    "observe",
-    "obtain",
-    "obvious",
-    "occur",
-    "ocean",
-    "october",
-    "odor",
-    "off",
-    "offer",
-    "office",
-    "often",
-    "oil",
-    "okay",
-    "old",
-    "olive",
-    "olympic",
-    "omit",
-    "once",
-    "one",
-    "onion",
-    "online",
-    "only",
-    "open",
-    "opera",
-    "opinion",
-    "oppose",
-    "option",
-    "orange",
-    "orbit",
-    "orchard",
-    "order",
-    "ordinary",
-    "organ",
-    "orient",
-    "original",
-    "orphan",
-    "ostrich",
-    "other",
-    "outdoor",
-    "outer",
-    "output",
-    "outside",
-    "oval",
-    "oven",
-    "over",
-    "own",
-    "owner",
-    "oxygen",
-    "oyster",
-    "ozone",
-    "pact",
-    "paddle",
-    "page",
-    "pair",
-    "palace",
-    "palm",
-    "panda",
-    "panel",
-    "panic",
-    "panther",
-    "paper",
-    "parade",
-    "parent",
-    "park",
-    "parrot",
-    "party",
-    "pass",
-    "patch",
-    "path",
-    "patient",
-    "patrol",
-    "pattern",
-    "pause",
-    "pave",
-    "payment",
-    "peace",
-    "peanut",
-    "pear",
-    "peasant",
-    "pelican",
-    "pen",
-    "penalty",
-    "pencil",
-    "people",
-    "pepper",
-    "perfect",
-    "permit",
-    "person",
-    "pet",
-    "phone",
-    "photo",
-    "phrase",
-    "physical",
-    "piano",
-    "picnic",
-    "picture",
-    "piece",
-    "pig",
-    "pigeon",
-    "pill",
-    "pilot",
-    "pink",
-    "pioneer",
-    "pipe",
-    "pistol",
-    "pitch",
-    "pizza",
-    "place",
-    "planet",
-    "plastic",
-    "plate",
-    "play",
-    "please",
-    "pledge",
-    "pluck",
-    "plug",
-    "plunge",
-    "poem",
-    "poet",
-    "point",
-    "polar",
-    "pole",
-    "police",
-    "pond",
-    "pony",
-    "pool",
-    "popular",
-    "portion",
-    "position",
-    "possible",
-    "post",
-    "potato",
-    "pottery",
-    "poverty",
-    "powder",
-    "power",
-    "practice",
-    "praise",
-    "predict",
-    "prefer",
-    "prepare",
-    "present",
-    "pretty",
-    "prevent",
-    "price",
-    "pride",
-    "primary",
-    "print",
-    "priority",
-    "prison",
-    "private",
-    "prize",
-    "problem",
-    "process",
-    "produce",
-    "profit",
-    "program",
-    "project",
-    "promote",
-    "proof",
-    "property",
-    "prosper",
-    "protect",
-    "proud",
-    "provide",
-    "public",
-    "pudding",
-    "pull",
-    "pulp",
-    "pulse",
-    "pumpkin",
-    "punch",
-    "pupil",
-    "puppy",
-    "purchase",
-    "purity",
-    "purpose",
-    "purse",
-    "push",
-    "put",
-    "puzzle",
-    "pyramid",
-    "quality",
-    "quantum",
-    "quarter",
-    "question",
-    "quick",
-    "quit",
-    "quiz",
-    "quote",
-    "rabbit",
-    "raccoon",
-    "race",
-    "rack",
-    "radar",
-    "radio",
-    "rail",
-    "rain",
-    "raise",
-    "rally",
-    "ramp",
-    "ranch",
-    "random",
-    "range",
-    "rapid",
-    "rare",
-    "rate",
-    "rather",
-    "raven",
-    "raw",
-    "razor",
-    "ready",
-    "real",
-    "reason",
-    "rebel",
-    "rebuild",
-    "recall",
-    "receive",
-    "recipe",
-    "record",
-    "recycle",
-    "reduce",
-    "reflect",
-    "reform",
-    "refuse",
-    "region",
-    "regret",
-    "regular",
-    "reject",
-    "relax",
-    "release",
-    "relief",
-    "rely",
-    "remain",
-    "remember",
-    "remind",
-    "remove",
-    "render",
-    "renew",
-    "rent",
-    "reopen",
-    "repair",
-    "repeat",
-    "replace",
-    "report",
-    "require",
-    "rescue",
-    "resemble",
-    "resist",
-    "resource",
-    "response",
-    "result",
-    "retire",
-    "retreat",
-    "return",
-    "reunion",
-    "reveal",
-    "review",
-    "reward",
-    "rhythm",
-    "rib",
-    "ribbon",
-    "rice",
-    "rich",
-    "ride",
-    "ridge",
-    "rifle",
-    "right",
-    "rigid",
-    "ring",
-    "riot",
-    "ripple",
-    "risk",
-    "ritual",
-    "rival",
-    "river",
-    "road",
-    "roast",
-    "robot",
-    "robust",
-    "rocket",
-    "romance",
-    "roof",
-    "rookie",
-    "room",
-    "rose",
-    "rotate",
-    "rough",
-    "round",
-    "route",
-    "royal",
-    "rubber",
-    "rude",
-    "rug",
-    "rule",
-    "run",
-    "runway",
-    "rural",
-    "sad",
-    "saddle",
-    "sadness",
-    "safe",
-    "sail",
-    "salad",
-    "salmon",
-    "salon",
-    "salt",
-    "salute",
-    "same",
-    "sample",
-    "sand",
-    "satisfy",
-    "satoshi",
-    "sauce",
-    "sausage",
-    "save",
-    "say",
-    "scale",
-    "scan",
-    "scare",
-    "scatter",
-    "scene",
-    "scheme",
-    "school",
-    "science",
-    "scissors",
-    "scorpion",
-    "scout",
-    "scrap",
-    "screen",
-    "script",
-    "scrub",
-    "sea",
-    "search",
-    "season",
-    "seat",
-    "second",
-    "secret",
-    "section",
-    "security",
-    "seed",
-    "seek",
-    "segment",
-    "select",
-    "sell",
-    "seminar",
-    "senior",
-    "sense",
-    "sentence",
-    "series",
-    "service",
-    "session",
-    "settle",
-    "setup",
-    "seven",
-    "shadow",
-    "shaft",
-    "shallow",
-    "share",
-    "shed",
-    "shell",
-    "sheriff",
-    "shield",
-    "shift",
-    "shine",
-    "ship",
-    "shiver",
-    "shock",
-    "shoe",
-    "shoot",
-    "shop",
-    "short",
-    "shoulder",
-    "shove",
-    "shrimp",
-    "shrug",
-    "shuffle",
-    "shy",
-    "sibling",
-    "sick",
-    "side",
-    "siege",
-    "sight",
-    "sign",
-    "silent",
-    "silk",
-    "silly",
-    "silver",
-    "similar",
-    "simple",
-    "since",
-    "sing",
-    "siren",
-    "sister",
-    "situate",
-    "six",
-    "size",
-    "skate",
-    "sketch",
-    "ski",
-    "skill",
-    "skin",
-    "skirt",
-    "skull",
-    "slab",
-    "slam",
-    "sleep",
-    "slender",
-    "slice",
-    "slide",
-    "slight",
-    "slim",
-    "slogan",
-    "slot",
-    "slow",
-    "slush",
-    "small",
-    "smart",
-    "smile",
-    "smoke",
-    "smooth",
-    "snack",
-    "snake",
-    "snap",
-    "sniff",
-    "snow",
-    "soap",
-    "soccer",
-    "social",
-    "sock",
-    "soda",
-    "soft",
-    "solar",
-    "soldier",
-    "solid",
-    "solution",
-    "solve",
-    "someone",
-    "song",
-    "soon",
-    "sorry",
-    "sort",
-    "soul",
-    "sound",
-    "soup",
-    "source",
-    "south",
-    "space",
-    "spare",
-    "spatial",
-    "spawn",
-    "speak",
-    "special",
-    "speed",
-    "spell",
-    "spend",
-    "sphere",
-    "spice",
-    "spider",
-    "spike",
-    "spin",
-    "spirit",
-    "split",
-    "spoil",
-    "sponsor",
-    "spoon",
-    "sport",
-    "spot",
-    "spray",
-    "spread",
-    "spring",
-    "spy",
-    "square",
-    "squeeze",
-    "squirrel",
-    "stable",
-    "stadium",
-    "staff",
-    "stage",
-    "stairs",
-    "stamp",
-    "stand",
-    "start",
-    "state",
-    "stay",
-    "steak",
-    "steel",
-    "stem",
-    "step",
-    "stereo",
-    "stick",
-    "still",
-    "sting",
-    "stock",
-    "stomach",
-    "stone",
-    "stool",
-    "story",
-    "stove",
-    "strategy",
-    "street",
-    "strike",
-    "strong",
-    "struggle",
-    "student",
-    "stuff",
-    "stumble",
-    "style",
-    "subject",
-    "submit",
-    "subway",
-    "success",
-    "such",
-    "sudden",
-    "suffer",
-    "sugar",
-    "suggest",
-    "suit",
-    "summer",
-    "sun",
-    "sunny",
-    "sunset",
-    "super",
-    "supply",
-    "supreme",
-    "sure",
-    "surface",
-    "surge",
-    "surprise",
-    "surround",
-    "survey",
-    "suspect",
-    "sustain",
-    "swallow",
-    "swamp",
-    "swap",
-    "swarm",
-    "swear",
-    "sweet",
-    "swift",
-    "swim",
-    "swing",
-    "switch",
-    "sword",
-    "symbol",
-    "symptom",
-    "syrup",
-    "system",
-    "table",
-    "tackle",
-    "tag",
-    "tail",
-    "talent",
-    "talk",
-    "tank",
-    "tape",
-    "target",
-    "task",
-    "taste",
-    "tattoo",
-    "taxi",
-    "teach",
-    "team",
-    "tell",
-    "ten",
-    "tenant",
-    "tennis",
-    "tent",
-    "term",
-    "test",
-    "text",
-    "thank",
-    "that",
-    "theme",
-    "then",
-    "theory",
-    "there",
-    "they",
-    "thing",
-    "this",
-    "thought",
-    "three",
-    "thrive",
-    "throw",
-    "thumb",
-    "thunder",
-    "ticket",
-    "tide",
-    "tiger",
-    "tilt",
-    "timber",
-    "time",
-    "tiny",
-    "tip",
-    "tired",
-    "tissue",
-    "title",
-    "toast",
-    "tobacco",
-    "today",
-    "toddler",
-    "toe",
-    "together",
-    "toilet",
-    "token",
-    "tomato",
-    "tomorrow",
-    "tone",
-    "tongue",
-    "tonight",
-    "tool",
-    "tooth",
-    "top",
-    "topic",
-    "topple",
-    "torch",
-    "tornado",
-    "tortoise",
-    "toss",
-    "total",
-    "tourist",
-    "toward",
-    "tower",
-    "town",
-    "toy",
-    "track",
-    "trade",
-    "traffic",
-    "tragic",
-    "train",
-    "transfer",
-    "trap",
-    "trash",
-    "travel",
-    "tray",
-    "treat",
-    "tree",
-    "trend",
-    "trial",
-    "tribe",
-    "trick",
-    "trigger",
-    "trim",
-    "trip",
-    "trophy",
-    "trouble",
-    "truck",
-    "true",
-    "truly",
-    "trumpet",
-    "trust",
-    "truth",
-    "try",
-    "tube",
-    "tuition",
-    "tumble",
-    "tuna",
-    "tunnel",
-    "turkey",
-    "turn",
-    "turtle",
-    "twelve",
-    "twenty",
-    "twice",
-    "twin",
-    "twist",
-    "two",
-    "type",
-    "typical",
-    "ugly",
-    "umbrella",
-    "unable",
-    "unaware",
-    "uncle",
-    "uncover",
-    "under",
-    "undo",
-    "unfair",
-    "unfold",
-    "unhappy",
-    "uniform",
-    "unique",
-    "unit",
-    "universe",
-    "unknown",
-    "unlock",
-    "until",
-    "unusual",
-    "unveil",
-    "update",
-    "upgrade",
-    "uphold",
-    "upon",
-    "upper",
-    "upset",
-    "urban",
-    "urge",
-    "usage",
-    "use",
-    "used",
-    "useful",
-    "useless",
-    "usual",
-    "utility",
-    "vacant",
-    "vacuum",
-    "vague",
-    "valid",
-    "valley",
-    "valve",
-    "van",
-    "vanish",
-    "vapor",
-    "various",
-    "vast",
-    "vault",
-    "vehicle",
-    "velvet",
-    "vendor",
-    "venture",
-    "venue",
-    "verb",
-    "verify",
-    "version",
-    "very",
-    "vessel",
-    "veteran",
-    "viable",
-    "vibrant",
-    "vicious",
-    "victory",
-    "video",
-    "view",
-    "village",
-    "vintage",
-    "violin",
-    "virtual",
-    "virus",
-    "visa",
-    "visit",
-    "visual",
-    "vital",
-    "vivid",
-    "vocal",
-    "voice",
-    "void",
-    "volcano",
-    "volume",
-    "vote",
-    "voyage",
-    "wage",
-    "wagon",
-    "wait",
-    "walk",
-    "wall",
-    "walnut",
-    "want",
-    "warfare",
-    "warm",
-    "warrior",
-    "wash",
-    "wasp",
-    "waste",
-    "water",
-    "wave",
-    "way",
-    "wealth",
-    "weapon",
-    "wear",
-    "weasel",
-    "weather",
-    "web",
-    "wedding",
-    "weekend",
-    "weird",
-    "welcome",
-    "west",
-    "wet",
-    "whale",
-    "what",
-    "wheat",
-    "wheel",
-    "when",
-    "where",
-    "whip",
-    "whisper",
-    "wide",
-    "width",
-    "wife",
-    "wild",
-    "will",
-    "win",
-    "window",
-    "wine",
-    "wing",
-    "wink",
-    "winner",
-    "winter",
-    "wire",
-    "wisdom",
-    "wise",
-    "wish",
-    "witness",
-    "wolf",
-    "woman",
-    "wonder",
-    "wood",
-    "wool",
-    "word",
-    "work",
-    "world",
-    "worry",
-    "worth",
-    "wrap",
-    "wreck",
-    "wrestle",
-    "wrist",
-    "write",
-    "wrong",
-    "yard",
-    "year",
-    "yellow",
-    "you",
-    "young",
-    "youth",
-    "zebra",
-    "zero",
-    "zone",
-    "zoo",
-};
-
-test "words_by_prefix" {
-    const lang: Language = .english;
-
-    var res = lang.wordsByPrefix("woo") orelse @panic("not expect");
-    try std.testing.expectEqualSlices([]const u8, &.{ "wood", "wool" }, res);
-
-    res = lang.wordsByPrefix("") orelse @panic("not expect");
-    try std.testing.expectEqual(res.len, 2048);
-
-    try std.testing.expect(lang.wordsByPrefix("woof") == null);
-}
diff --git a/src/core/bip39/pbkdf2.zig b/src/core/bip39/pbkdf2.zig
deleted file mode 100644
index 5f773f3..0000000
--- a/src/core/bip39/pbkdf2.zig
+++ /dev/null
@@ -1,143 +0,0 @@
-const std = @import("std");
-const SALT_PREFIX = "mnemonic";
-
-const Hmac = std.crypto.auth.hmac.sha2.HmacSha512;
-const Sha512 = std.crypto.hash.sha2.Sha512;
-
-/// Calculate the binary size of the mnemonic.
-fn mnemonicByteLen(mnemonic: []const []const u8) usize {
-    var len: usize = 0;
-    for (0.., mnemonic) |i, word| {
-        if (i > 0) {
-            len += 1;
-        }
-
-        len += word.len;
-    }
-    return len;
-}
-
-/// Wrote the mnemonic in binary form into the hash engine.
-fn mnemonicWriteInto(mnemonic: []const []const u8, engine: *Sha512) void {
-    for (0.., mnemonic) |i, word| {
-        if (i > 0) {
-            engine.update(" ");
-        }
-        engine.update(word);
-    }
-}
-
-/// Create an HMAC engine from the passphrase.
-/// We need a special method because we can't allocate a new byte
-/// vector for the entire serialized mnemonic.
-fn createHmacEngine(mnemonic: []const []const u8) Hmac {
-    // Inner code is borrowed from the bitcoin_hashes::hmac::HmacEngine::new method.
-    var ipad = [_]u8{0x36} ** 128;
-    var opad = [_]u8{0x5c} ** 128;
-
-    var iengine = Sha512.init(.{});
-
-    if (mnemonicByteLen(mnemonic) > Sha512.block_length) {
-        const hash = v: {
-            var engine = Sha512.init(.{});
-            mnemonicWriteInto(mnemonic, &engine);
-            var final: [Sha512.digest_length]u8 = undefined;
-            engine.final(&final);
-            break :v final;
-        };
-
-        for (ipad[0..64], hash) |*b_i, b_h| {
-            b_i.* = b_i.* ^ b_h;
-        }
-
-        for (opad[0..64], hash) |*b_o, b_h| {
-            b_o.* = b_o.* ^ b_h;
-        }
-    } else {
-        // First modify the first elements from the prefix.
-        var cursor: usize = 0;
-        for (0.., mnemonic) |i, word| {
-            if (i > 0) {
-                ipad[cursor] ^= ' ';
-                opad[cursor] ^= ' ';
-                cursor += 1;
-            }
-
-            const min_len = @min(ipad.len - cursor, word.len);
-            for (ipad[cursor .. cursor + min_len], word[0..min_len]) |*b_i, b_h| {
-                b_i.* = b_i.* ^ b_h;
-            }
-
-            for (opad[cursor .. cursor + min_len], word[0..min_len]) |*b_o, b_h| {
-                b_o.* = b_o.* ^ b_h;
-            }
-
-            cursor += word.len;
-            // assert!(cursor <= sha512::HashEngine::BLOCK_SIZE, "mnemonic_byte_len is broken");
-        }
-    }
-
-    iengine.update(ipad[0..Sha512.block_length]);
-
-    return Hmac{
-        .o_key_pad = opad[0..Sha512.block_length].*,
-        .hash = iengine,
-    };
-}
-
-inline fn xor(res: []u8, salt: []const u8) void {
-    // length mismatch in xor
-    std.debug.assert(salt.len >= res.len);
-    const min_len = @min(res.len, salt.len);
-    for (res[0..min_len], salt[0..min_len]) |*a, b| {
-        a.* = a.* ^ b;
-    }
-}
-
-/// PBKDF2-HMAC-SHA512 implementation using bitcoin_hashes.
-pub fn pbkdf2(mnemonic: []const []const u8, unprefixed_salt: []const u8, c: usize, res: []u8) void {
-    const prf = createHmacEngine(mnemonic);
-    @memset(res, 0);
-
-    // var pprf = prf;
-
-    // var prf_buf: [Hmac.mac_length]u8 = undefined;
-    // pprf.final(&prf_buf);
-
-    // std.log.warn("pprf :{any}", .{prf_buf});
-
-    var i: usize = 0;
-
-    while (i < res.len) : ({
-        i += Sha512.digest_length;
-    }) {
-        const chunk_too = @min(res.len, i + Sha512.digest_length);
-        const chunk: []u8 = res[i..chunk_too];
-        var salt = v: {
-            var prfc = prf;
-            prfc.update(SALT_PREFIX);
-            prfc.update(unprefixed_salt);
-
-            var buf: [4]u8 = undefined;
-            std.mem.writeInt(u32, &buf, @truncate(i + 1), .big);
-
-            prfc.update(&buf);
-
-            var salt: [Hmac.mac_length]u8 = undefined;
-
-            prfc.final(&salt);
-
-            xor(chunk, &salt);
-            break :v salt;
-        };
-
-        for (1..c) |_| {
-            var prfc = prf;
-
-            prfc.update(&salt);
-
-            prfc.final(&salt);
-            xor(chunk, &salt);
-        }
-    }
-}
diff --git a/src/core/lib.zig b/src/core/lib.zig
index 536ac92..5b56d5f 100644
--- a/src/core/lib.zig
+++ b/src/core/lib.zig
@@ -1,6 +1,4 @@
-pub const bip32 = @import("bip32/bip32.zig");
 pub const dhke = @import("dhke.zig");
 pub const secret = @import("secret.zig");
 pub const amount = @import("amount.zig");
 pub const nuts = @import("nuts/lib.zig");
-pub const bip39 = @import("bip39/bip39.zig");
diff --git a/src/core/nuts/nut02/nut02.zig b/src/core/nuts/nut02/nut02.zig
index 99afaff..c93bdc7 100644
--- a/src/core/nuts/nut02/nut02.zig
+++ b/src/core/nuts/nut02/nut02.zig
@@ -8,7 +8,7 @@ const Keys = @import("../nut01/nut01.zig").Keys;
 const MintKeys = @import("../nut01/nut01.zig").MintKeys;
 const MintKeyPair = @import("../nut01/nut01.zig").MintKeyPair;
 const secp256k1 = @import("secp256k1");
-const bip32 = @import("../../bip32/bip32.zig");
+const bip32 = @import("bitcoin").bitcoin.bip32;
 
 /// Keyset version
 pub const KeySetVersion = enum {
diff --git a/src/core/nuts/nut13/nut13.zig b/src/core/nuts/nut13/nut13.zig
index ccdaa47..1ae7b87 100644
--- a/src/core/nuts/nut13/nut13.zig
+++ b/src/core/nuts/nut13/nut13.zig
@@ -10,12 +10,12 @@ const nut00 = @import("../nut00/lib.zig");
 const BlindedMessage = nut00.BlindedMessage;
 const PreMint = nut00.PreMint;
 const PreMintSecrets = nut00.PreMintSecrets;
-const bip32 = @import("../../bip32/bip32.zig");
+const bip32 = @import("bitcoin").bitcoin.bip32;
 const std = @import("std");
 const amount_lib = @import("../../amount.zig");
 const dhke = @import("../../dhke.zig");
 const helper = @import("../../../helper/helper.zig");
-const bip39 = @import("../../bip39/bip39.zig");
+const bip39 = @import("bitcoin").bitcoin.bip39;
 
 fn derivePathFromKeysetId(id: Id) ![3]bip32.ChildNumber {
     const index: u32 = @intCast(try id.toU64() % ((std.math.powi(u64, 2, 31) catch unreachable) - 1));
diff --git a/src/lib.zig b/src/lib.zig
index 467eba8..7ce22c1 100644
--- a/src/lib.zig
+++ b/src/lib.zig
@@ -1,12 +1,7 @@
 const std = @import("std");
 pub const core = @import("core/lib.zig");
-// pub usingnamespace @import("core/lib.zig");
-// TODO return after fix mint
-// pub usingnamespace @import("mint/lib.zig");
-// pub const bech32 = @import("bech32/bech32.zig");
 
 test {
     std.testing.log_level = .warn;
     std.testing.refAllDeclsRecursive(@This());
-    // std.testing.refAllDeclsRecursive(bech32);
 }
diff --git a/src/mint/lightning/invoices/invoice.zig b/src/mint/lightning/invoices/invoice.zig
index 236c531..9d90ba4 100644
--- a/src/mint/lightning/invoices/invoice.zig
+++ b/src/mint/lightning/invoices/invoice.zig
@@ -2,7 +2,7 @@ const std = @import("std");
 const errors = @import("error.zig");
 const core = @import("../../../core/lib.zig");
 const constants = @import("constants.zig");
-const bech32 = @import("../../../bech32/bech32.zig");
+const bech32 = @import("bitcoin").bech32;
 const secp256k1 = @import("secp256k1");
 
 /// Construct the invoice's HRP and signatureless data into a preimage to be hashed.