-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from eltNEG/feat/wif
wip: Implement wif
- Loading branch information
Showing
3 changed files
with
117 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub const Wif = @import("wif.zig").WIF; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
const PrivateKey = @import("../bips/bip32/key.zig").PrivateKey; | ||
const Network = @import("../bips/bip32/bip32.zig").Network; | ||
const std = @import("std"); | ||
const Base58Encoder = @import("../base58/base58.zig").Encoder; | ||
const secp256k1 = @import("secp256k1"); | ||
|
||
/// WIF as defined in https://en.bitcoin.it/wiki/Wallet_import_format | ||
pub const WIF_PREFIX_MAINNET: u8 = 0x80; | ||
pub const WIF_PREFIX_TESTNET: u8 = 0xef; | ||
pub const WIF_COMPRESSED_FLAG: u8 = 0x01; | ||
|
||
pub const WIFDecodeError = error{}; | ||
|
||
pub const WIF = struct { | ||
const Self = @This(); | ||
inner: []u8, | ||
|
||
pub fn fromPrivateKey(private_key: PrivateKey) !Self { | ||
const max_size = 1 + 32 + 1 + 4; // prefix + key + compressed flag + checksum | ||
var actual_size: u8 = max_size - 1; | ||
if (private_key.compressed) { | ||
actual_size += 1; | ||
} | ||
var buf = [_]u8{0} ** max_size; | ||
|
||
if (private_key.network == Network.MAINNET) { | ||
buf[0] = WIF_PREFIX_MAINNET; | ||
} else { | ||
buf[0] = WIF_PREFIX_TESTNET; | ||
} | ||
|
||
@memcpy(buf[1..33], private_key.inner.data[0..32]); | ||
|
||
if (private_key.compressed) { | ||
buf[33] = WIF_COMPRESSED_FLAG; | ||
} | ||
|
||
var sha256 = std.crypto.hash.sha2.Sha256.init(.{}); | ||
var out256: [std.crypto.hash.sha2.Sha256.digest_length]u8 = undefined; | ||
|
||
sha256.update(buf[0 .. actual_size - 4]); | ||
sha256.final(&out256); | ||
|
||
sha256 = std.crypto.hash.sha2.Sha256.init(.{}); | ||
|
||
sha256.update(out256[0..std.crypto.hash.sha2.Sha256.digest_length]); | ||
sha256.final(&out256); | ||
|
||
@memcpy(buf[actual_size - 4 .. actual_size], out256[0..4]); | ||
|
||
// base58 encode | ||
var encoder = Base58Encoder{}; | ||
var encode_buf = [_]u8{0} ** 52; // max wif len is 52 | ||
const encode_size = encoder.encode(buf[0..actual_size], &encode_buf); | ||
const wif = WIF{ | ||
.inner = encode_buf[0..encode_size], | ||
}; | ||
return wif; | ||
} | ||
|
||
pub fn toString(self: WIF) []u8 { | ||
return self.inner; | ||
} | ||
|
||
pub fn fromString(wif: []const u8) !WIF { | ||
_ = wif; | ||
return WIF{ .inner = undefined }; | ||
} | ||
|
||
pub fn toPrivateKey(self: WIF) !PrivateKey { | ||
_ = self; | ||
return PrivateKey{ .network = Network.MAINNET, .compressed = false, .inner = secp256k1.SecretKey{ .data = [_]u8{0} ** 32 } }; | ||
} | ||
}; | ||
|
||
test "WIF with compressed private key" { | ||
const privateKey = PrivateKey{ .network = Network.MAINNET, .compressed = true, .inner = try secp256k1.SecretKey.fromString("7bea4d472aa93e49321bbde5db88b126b9435482e1f39d84664530a5f40408cd") }; | ||
const wif = try WIF.fromPrivateKey(privateKey); | ||
const expected = "L1NawHPsZVHsnW4DUBC7K36LzXfcsLck85fMSoEGyT4LMZv9xSjD"; | ||
const actual = wif.toString(); | ||
try std.testing.expectEqualSlices(u8, expected[0..], actual[0..]); | ||
} | ||
|
||
test "WIF with uncompressed private key 2" { | ||
const privateKey = PrivateKey{ .network = Network.MAINNET, .compressed = false, .inner = try secp256k1.SecretKey.fromString("0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D") }; | ||
const wif = try WIF.fromPrivateKey(privateKey); | ||
const expected = "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ"; | ||
const actual = wif.toString(); | ||
try std.testing.expectEqualSlices(u8, expected[0..], actual[0..]); | ||
} | ||
|
||
test "WIF with uncompressed private key" { | ||
const privateKey = PrivateKey{ .network = Network.MAINNET, .compressed = false, .inner = try secp256k1.SecretKey.fromString("46605abb568e1566834e7ee57e271964534d8fc3b23ca5f546b081ad7e233671") }; | ||
const wif = try WIF.fromPrivateKey(privateKey); | ||
const expected = "5JMHFZHuMcVnqVBARmg3jW3LMxdB6qbJtesC5xhXRji6wabvbWu"; | ||
const actual = wif.toString(); | ||
// std.debug.print("actual========: {s}\n", .{actual}); | ||
try std.testing.expectEqualSlices(u8, expected[0..], actual[0..]); | ||
} | ||
|
||
test "WIF with compressed testnet private key" { | ||
const privateKey = PrivateKey{ .network = Network.TESTNET, .compressed = true, .inner = try secp256k1.SecretKey.fromString("46605abb568e1566834e7ee57e271964534d8fc3b23ca5f546b081ad7e233671") }; | ||
const wif = try WIF.fromPrivateKey(privateKey); | ||
const expected = "cPwWCAXTX3NLUSq7zjzURugN5jp5FDa832H13KJNoJARUPsaTJ9G"; | ||
const actual = wif.toString(); | ||
try std.testing.expectEqualSlices(u8, expected[0..], actual[0..]); | ||
} | ||
|
||
test "WIF with uncompressed testnet private key" { | ||
const privateKey = PrivateKey{ .network = Network.TESTNET, .compressed = false, .inner = try secp256k1.SecretKey.fromString("46605abb568e1566834e7ee57e271964534d8fc3b23ca5f546b081ad7e233671") }; | ||
const wif = try WIF.fromPrivateKey(privateKey); | ||
const expected = "927uqJ7SwqZvoYgT47Zxc6bJ1cytG18WEbj9Ab42mUT9icaLVhF"; | ||
const actual = wif.toString(); | ||
try std.testing.expectEqualSlices(u8, expected[0..], actual[0..]); | ||
} |