Skip to content

Commit aecfa61

Browse files
Bech32 Encoding/Decoding and Blake2b Hashing Commands
New Commands - EncodeBech32Command - DecodeBech32Command - HashBlake2bCommand Co-authored-by: safestak-keith <keith@safestak.com>
1 parent 0d6ef78 commit aecfa61

16 files changed

+551
-14
lines changed

.github/workflows/release.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ jobs:
3737
with:
3838
dotnet-version: ${{ env.DOTNET_VERSION }}
3939

40+
- name: Set release outputs
41+
id: release-params
42+
run: |
43+
VERSION_TAG=$(git describe --tags --abbrev=0)
44+
RELEASE_NAME="cscli-$VERSION_TAG-${{ matrix.target }}"
45+
echo "::set-output name=release_name::$RELEASE_NAME"
46+
4047
- name: Build
4148
shell: bash
4249
run: |
43-
tag=$(git describe --tags --abbrev=0)
44-
release_name="cscli-$tag-${{ matrix.target }}"
45-
dotnet publish Src/ConsoleTool/Cscli.ConsoleTool.csproj -r "${{ matrix.target }}" -c Release -o "$release_name" "-p:PublishSingleFile=true" "-p:AssemblyName=cscli.${{ matrix.target }}" --self-contained true
50+
dotnet publish Src/ConsoleTool/Cscli.ConsoleTool.csproj -r "${{ matrix.target }}" -c Release -o "${{steps.release-params.outputs.release_name}}" "-p:PublishSingleFile=true" "-p:PublishTrimmed=true" "-p:AssemblyName=cscli.${{ matrix.target }}" --self-contained true
4651
4752
- name: Upload Build Artifact
4853
uses: actions/upload-artifact@v2
4954
with:
5055
name: Application_Artifact
51-
path: "cscli-$tag-${{ matrix.target }}/*"
56+
path: "${{steps.release-params.outputs.release_name}}/*"
5257

5358
- name: Publish to GitHub Release
5459
uses: softprops/action-gh-release@v1
5560
with:
56-
files: "cscli-$tag-${{ matrix.target }}/*"
61+
files: "${{steps.release-params.outputs.release_name}}/*"
5762
env:
5863
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ dotnet restore
5252
dotnet build --no-restore
5353
dotnet test --no-build
5454
dotnet pack --no-build Src/ConsoleTool/CsCli.ConsoleTool.csproj -o nupkg -c Release
55-
dotnet tool install --global --add-source ./nupkg cscli --version 0.0.5-local-branch.1
55+
dotnet tool install --global --add-source ./nupkg cscli --version 0.0.6-local-branch.1
5656
```
5757
</details>
5858

@@ -63,8 +63,9 @@ dotnet tool install --global --add-source ./nupkg cscli --version 0.0.5-local-br
6363
### Overview and Help
6464
```console
6565
$ cscli --help
66-
cscli v0.0.5
66+
cscli v0.0.6
6767
A cross-platform tool for building and interacting with Cardano wallet primitives (i.e. recovery-phrases, keys, addresses and transactions).
68+
Please see https://github.com/CardanoSharp/cscli from more detailed documentation.
6869

6970
USAGE: cscli (OPTION | COMMAND)
7071

@@ -80,13 +81,17 @@ Available commands:
8081
wallet key policy derive --recovery-phrase "<string>" [--language <language>] [--passphrase "<string>"] [--policy-index <derivation-index>] [--verification-key-file <string>] [--signing-key-file <string>]
8182
wallet address stake derive --recovery-phrase "<string>" --network-type <network-type> [--language <language>] [--passphrase "<string>"] [--account-index <derivation-index>] [--address-index <derivation-index>]
8283
wallet address payment derive --recovery-phrase "<string>" --network-type <network-type> --payment-address-type <payment-address-type> [--language <language>] [--passphrase "<string>"] [--account-index <derivation-index>] [--address-index <derivation-index>] [--stake-account-index <derivation-index>] [--stake-address-index <derivation-index>]
84+
bech32 encode --value "<hex_string>" --prefix "<string>"
85+
bech32 decode --value "<bech32_string>"
86+
blake2b hash --value "<hex_string>" --length <digest_length>
8387

8488
Arguments:
8589
<size> ::= 9 | 12 | 15 | 18 | 21 | 24(default)
8690
<language> ::= english(default)|chinesesimplified|chinesetraditional|french|italian|japanese|korean|spanish|czech|portuguese
8791
<derivation-index> ::= 0(default) | 1 | .. | 2147483647
8892
<network-type> ::= testnet | mainnet
8993
<payment-address-type> ::= enterprise | base
94+
<digest_length> ::= 160 | 224 | 256 | 512
9095
```
9196

9297
### Generate Recovery Phrase
@@ -247,5 +252,23 @@ $ cat policy_0.vkey
247252
```
248253
</details>
249254

255+
### Bech32 Decode
256+
```console
257+
$ cscli bech32 decode --value "$(cat pay_0_0.addr)"
258+
61282e5ee5d1e89e04fa81382df239d6733409875d75b480c879f58600
259+
```
260+
261+
### Bech32 Encode
262+
```console
263+
$ cscli bech32 encode --value 61282e5ee5d1e89e04fa81382df239d6733409875d75b480c879f58600 --prefix addr
264+
addr1vy5zuhh9685fup86syuzmu3e6eengzv8t46mfqxg086cvqqrukl6w
265+
```
266+
267+
### Blake2b Hash
268+
```console
269+
$ cscli blake2b hash --length 224 --value 1872bc5ecc95b419de3f72544a6656ceb9a813755544618bb6b4dcc230ed9721
270+
9df9179beb0ce89f84025e02ae11c18b3003e7690149caa662fafd01
271+
```
272+
250273
## Contributing
251-
Please see [CONTRIBUTING.md](./CONTRIBUTING.md)
274+
Please see [CONTRIBUTING.md](./CONTRIBUTING.md)

Src/ConsoleTool/CommandParser.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ private static ICommand ParseCommands(string intent, string[] args) =>
4343
"wallet" => ParseWalletCommands(intent, args),
4444
//"query" => ParseQueryCommands(intent, args), // TODO: query via Blockfrost/Koios integration
4545
//"tx" => ParseTxCommands(intent, args), // TODO: Easier Tx creation and submission via Blockfrost/Koios integration
46+
"bech32" or "blake2b" => ParseEncodingHashingCommands(intent, args),
4647
_ => new ShowInvalidArgumentCommand(intent)
4748
};
4849

@@ -59,6 +60,16 @@ private static ICommand ParseWalletCommands(string intent, string[] args) =>
5960
_ => new ShowInvalidArgumentCommand(intent)
6061
};
6162

63+
private static ICommand ParseEncodingHashingCommands(string intent, string[] args) =>
64+
intent switch
65+
{
66+
"bech32 encode" => BuildCommand<EncodeBech32Command>(args),
67+
"bech32 decode" => BuildCommand<DecodeBech32Command>(args),
68+
"blake2b hash" => BuildCommand<HashBlake2bCommand>(args),
69+
_ => new ShowInvalidArgumentCommand(intent)
70+
};
71+
72+
6273
private static ICommand BuildCommand<T>(
6374
string[] args)
6475
where T : ICommand
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using CardanoSharp.Wallet.Encoding;
2+
using CardanoSharp.Wallet.Extensions;
3+
4+
namespace Cscli.ConsoleTool.Commands;
5+
6+
public class DecodeBech32Command : ICommand
7+
{
8+
public string Value { get; init; } = string.Empty;
9+
10+
public ValueTask<CommandResult> ExecuteAsync(CancellationToken ct)
11+
{
12+
if (string.IsNullOrEmpty(Value))
13+
{
14+
return ValueTask.FromResult(CommandResult.FailureInvalidOptions(
15+
$"Invalid option --value is required."));
16+
}
17+
if (!Bech32.IsValid(Value))
18+
{
19+
return ValueTask.FromResult(CommandResult.FailureInvalidOptions(
20+
$"Invalid option --value {Value} is not a valid bech32 encoding."));
21+
}
22+
23+
try
24+
{
25+
var hex = Bech32
26+
.Decode(Value, out var ver, out var prefix)
27+
.ToStringHex();
28+
var result = CommandResult.Success(hex);
29+
return ValueTask.FromResult(result);
30+
}
31+
catch (Exception ex)
32+
{
33+
return ValueTask.FromResult(
34+
CommandResult.FailureUnhandledException("Unexpected error", ex));
35+
}
36+
}
37+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using CardanoSharp.Wallet.Encoding;
2+
3+
namespace Cscli.ConsoleTool.Commands;
4+
5+
public class EncodeBech32Command : ICommand
6+
{
7+
public string Prefix { get; init; } = string.Empty;
8+
public string Value { get; init; } = string.Empty;
9+
10+
public ValueTask<CommandResult> ExecuteAsync(CancellationToken ct)
11+
{
12+
if (string.IsNullOrEmpty(Value))
13+
{
14+
return ValueTask.FromResult(CommandResult.FailureInvalidOptions(
15+
$"Invalid option --value is required"));
16+
}
17+
18+
try
19+
{
20+
var rawBytesValue = Convert.FromHexString(Value);
21+
var hex = Bech32.Encode(rawBytesValue, Prefix);
22+
var result = CommandResult.Success(hex);
23+
return ValueTask.FromResult(result);
24+
}
25+
catch (FormatException ex)
26+
{
27+
return ValueTask.FromResult(
28+
CommandResult.FailureInvalidOptions($"Invalid option --value {ex.Message}"));
29+
}
30+
catch (Exception ex)
31+
{
32+
return ValueTask.FromResult(
33+
CommandResult.FailureUnhandledException("Unexpected error", ex));
34+
}
35+
}
36+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Blake2Fast;
2+
using CardanoSharp.Wallet.Extensions;
3+
using System.Collections.Immutable;
4+
5+
namespace Cscli.ConsoleTool.Commands;
6+
7+
public class HashBlake2bCommand : ICommand
8+
{
9+
private static readonly ImmutableArray<int> HashAlgorithmLengths = ImmutableArray.Create(new[]
10+
{
11+
160, // Assets
12+
224, // Keys/Addresses/SimpleScript/PlutusScript
13+
256, // Transactions
14+
512 // Wallet checksums
15+
});
16+
17+
public int Length { get; init; } = 224;
18+
public string Value { get; init; } = string.Empty;
19+
20+
public ValueTask<CommandResult> ExecuteAsync(CancellationToken ct)
21+
{
22+
if (string.IsNullOrEmpty(Value))
23+
{
24+
return ValueTask.FromResult(CommandResult.FailureInvalidOptions(
25+
$"Invalid option --value is required"));
26+
}
27+
if (!HashAlgorithmLengths.Contains(Length))
28+
{
29+
return ValueTask.FromResult(CommandResult.FailureInvalidOptions(
30+
$"Invalid option --length {Length} is not supported"));
31+
}
32+
33+
try
34+
{
35+
var digestLengthInBytes = Length / 8;
36+
var rawBytesValue = Convert.FromHexString(Value);
37+
var digest = Blake2b.ComputeHash(digestLengthInBytes, rawBytesValue);
38+
var digestHex = digest.ToStringHex();
39+
var result = CommandResult.Success(digestHex);
40+
return ValueTask.FromResult(result);
41+
}
42+
catch (FormatException ex)
43+
{
44+
return ValueTask.FromResult(
45+
CommandResult.FailureInvalidOptions($"Invalid option --value {ex.Message}"));
46+
}
47+
catch (Exception ex)
48+
{
49+
return ValueTask.FromResult(
50+
CommandResult.FailureUnhandledException("Unexpected error", ex));
51+
}
52+
}
53+
}

Src/ConsoleTool/Commands/ShowBaseHelpCommand.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public ValueTask<CommandResult> ExecuteAsync(CancellationToken ct)
1111
.Version;
1212
var helpText = $@"cscli v{versionString}
1313
A cross-platform tool for building and interacting with Cardano's wallet primitives (i.e. recovery-phrases, keys, addresses and transactions).
14+
Please see https://github.com/CardanoSharp/cscli from more detailed documentation.
1415
1516
USAGE: cscli (OPTION | COMMAND)
1617
@@ -26,13 +27,17 @@ wallet key payment derive --recovery-phrase ""<string>"" [--language <language>]
2627
wallet key policy derive --recovery-phrase ""<string>"" [--language <language>] [--passphrase ""<string>""] [--policy-index <derivation-index>] [--verification-key-file <string>] [--signing-key-file <string>]
2728
wallet address stake derive --recovery-phrase ""<string>"" --network-type <network-type> [--language <language>] [--passphrase ""<string>""] [--account-index <derivation-index>] [--address-index <derivation-index>]
2829
wallet address payment derive --recovery-phrase ""<string>"" --network-type <network-type> --payment-address-type <payment-address-type> [--language <language>] [--passphrase ""<string>""] [--account-index <derivation-index>] [--address-index <derivation-index>] [--stake-account-index <derivation-index>] [--stake-address-index <derivation-index>]
30+
bech32 encode --value ""<hex_string>"" --prefix ""<string>""
31+
bech32 decode --value ""<bech32_string>""
32+
blake2b hash --value ""<hex_string>"" --length <digest_length>
2933
3034
Arguments:
3135
<size> ::= 9 | 12 | 15 | 18 | 21 | 24(default)
3236
<language> ::= english(default)|chinesesimplified|chinesetraditional|french|italian|japanese|korean|spanish|czech|portuguese
3337
<derivation-index> ::= 0(default) | 1 | .. | 2147483647
3438
<network-type> ::= testnet | mainnet
3539
<payment-address-type> ::= enterprise | base
40+
<digest_length> ::= 160 | 224 | 256 | 512
3641
";
3742
return ValueTask.FromResult(CommandResult.Success(helpText));
3843
}

Src/ConsoleTool/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,4 @@ public static class Constants
4848
{ "--network-tag", "networkTag" },
4949
//{ "--output-format", "outputFormat" },
5050
};
51-
}
51+
}

Src/ConsoleTool/Cscli.ConsoleTool.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<None Include="..\..\README.md" Link="README.md" Pack="true" PackagePath="\" />
3232
</ItemGroup>
3333
<ItemGroup>
34-
<PackageReference Include="CardanoSharp.Wallet" Version="2.0.2" />
34+
<PackageReference Include="CardanoSharp.Wallet" Version="2.1.0" />
3535
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
3636
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
3737
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="6.0.0" />

Src/ConsoleTool/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ private static CancellationTokenSource SetupUserInputCancellationTokenSource()
2727
};
2828
return cts;
2929
}
30-
}
30+
}

0 commit comments

Comments
 (0)