7 people like it.
Like the snippet!
Random-key-generator and Base-58-encoding
Generate random hex-string and calculate base58encode. I made these for some initial BTC-testing, but didn't test too much... seems to work, but would need some unit-tests... :-)
Feel free to update or add new versions.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
|
module BtcTesting
open System
open System.Security.Cryptography
/// https://en.bitcoin.it/wiki/Base58Check_encoding
let base58encode (hash:byte[]) =
let code_string = ['1'..'9']@['A'..'H']@['J'..'N']@['P'..'Z']@['a'..'k']@['m'..'z'] |> List.toArray
let data = hash |> Array.toList
let rec toBigInt = function
|[], acc -> acc
|h::t, acc -> toBigInt(t, acc*256I + bigint(int h))
let rec base58encodeLeft = function
| i,acc when i>0I ->
let reminder = ref 0I
let dividend = bigint.DivRem(i, 58I, reminder)
let char = code_string.[(int)reminder.contents]
base58encodeLeft(dividend, char::acc)
| _,acc -> acc
let appendOnes =
let rec insertOnes = function
| h::t,acc when h=0uy -> insertOnes(t, '1'::acc)
| _,acc -> acc
insertOnes(data, [])
let big = toBigInt(data, 0I)
let encoded = appendOnes @ base58encodeLeft(big, []) |> List.toArray
String(encoded)
/// String to byte-array. You could use Seq.pairwise, but this is taken from:
/// http://www.fssnip.net/gf
let fromHex (s:string) =
s
|> Seq.windowed 2
|> Seq.mapi (fun i j -> (i,j))
|> Seq.filter (fun (i,j) -> i % 2=0)
|> Seq.map (fun (_,j) -> Byte.Parse(new System.String(j),System.Globalization.NumberStyles.AllowHexSpecifier))
|> Array.ofSeq
/// https://en.bitcoin.it/wiki/Wallet_import_format
let keyToWif (key:string) =
use sha = new SHA256Managed()
let extended = "80"+key |> fromHex
let hashCheck = extended
|> sha.ComputeHash
|> sha.ComputeHash
Array.append extended hashCheck.[0..3]
|> Array.rev
|> base58encode
/// Generates random HEX-string
// More random options are available in MathNet.Numerics.FSharp Nuget-package
// namespace MathNet.Numerics.Random
let privateKey() =
let chars = ['a'..'f']@['0'..'9'] |> List.toArray
let length = chars.Length
let data = Array.zeroCreate 64
use provider = new RNGCryptoServiceProvider()
do provider.GetNonZeroBytes(data)
let random = data |> Array.map(fun b -> chars.[(int)b % length ])
System.String(random)
// let pk = privateKey();;
// pk |> keyToWif;;
|
module BtcTesting
namespace System
namespace System.Security
namespace System.Security.Cryptography
val base58encode : hash:byte [] -> String
https://en.bitcoin.it/wiki/Base58Check_encoding
val hash : byte []
Multiple items
val byte : value:'T -> byte (requires member op_Explicit)
--------------------
type byte = Byte
val code_string : char []
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IReadOnlyList<'T>
interface IReadOnlyCollection<'T>
interface IEnumerable
interface IEnumerable<'T>
member GetReverseIndex : rank:int * offset:int -> int
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
...
val toArray : list:'T list -> 'T []
val data : byte list
type Array =
member Clone : unit -> obj
member CopyTo : array:Array * index:int -> unit + 1 overload
member GetEnumerator : unit -> IEnumerator
member GetLength : dimension:int -> int
member GetLongLength : dimension:int -> int64
member GetLowerBound : dimension:int -> int
member GetUpperBound : dimension:int -> int
member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
member Initialize : unit -> unit
member IsFixedSize : bool
...
val toList : array:'T [] -> 'T list
val toBigInt : (byte list * Numerics.BigInteger -> Numerics.BigInteger)
val acc : Numerics.BigInteger
val h : byte
val t : byte list
type bigint = Numerics.BigInteger
Multiple items
val int : value:'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
val base58encodeLeft : (Numerics.BigInteger * char list -> char list)
val i : Numerics.BigInteger
val acc : char list
val reminder : Numerics.BigInteger ref
Multiple items
val ref : value:'T -> 'T ref
--------------------
type 'T ref = Ref<'T>
val dividend : Numerics.BigInteger
Numerics.BigInteger.DivRem(dividend: Numerics.BigInteger, divisor: Numerics.BigInteger, remainder: byref<Numerics.BigInteger>) : Numerics.BigInteger
Multiple items
val char : char
--------------------
type char = Char
val appendOnes : char list
val insertOnes : (byte list * char list -> char list)
val big : Numerics.BigInteger
val encoded : char []
Multiple items
type String =
new : value:char[] -> string + 8 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool + 3 overloads
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 3 overloads
member EnumerateRunes : unit -> StringRuneEnumerator
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
...
--------------------
String(value: char []) : String
String(value: nativeptr<char>) : String
String(value: nativeptr<sbyte>) : String
String(value: ReadOnlySpan<char>) : String
String(c: char, count: int) : String
String(value: char [], startIndex: int, length: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
val fromHex : s:string -> byte []
String to byte-array. You could use Seq.pairwise, but this is taken from:
http://www.fssnip.net/gf
val s : string
Multiple items
val string : value:'T -> string
--------------------
type string = String
module Seq
from Microsoft.FSharp.Collections
val windowed : windowSize:int -> source:seq<'T> -> seq<'T []>
val mapi : mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U>
val i : int
val j : char []
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
type Byte =
struct
member CompareTo : value:obj -> int + 1 overload
member Equals : obj:obj -> bool + 1 overload
member GetHashCode : unit -> int
member GetTypeCode : unit -> TypeCode
member ToString : unit -> string + 3 overloads
member TryFormat : destination:Span<char> * charsWritten:int * ?format:ReadOnlySpan<char> * ?provider:IFormatProvider -> bool
static val MaxValue : byte
static val MinValue : byte
static member Parse : s:string -> byte + 4 overloads
static member TryParse : s:string * result:byte -> bool + 3 overloads
end
Byte.Parse(s: string) : byte
Byte.Parse(s: string, provider: IFormatProvider) : byte
Byte.Parse(s: string, style: Globalization.NumberStyles) : byte
Byte.Parse(s: ReadOnlySpan<char>,?style: Globalization.NumberStyles,?provider: IFormatProvider) : byte
Byte.Parse(s: string, style: Globalization.NumberStyles, provider: IFormatProvider) : byte
namespace System.Globalization
type NumberStyles =
| None = 0
| AllowLeadingWhite = 1
| AllowTrailingWhite = 2
| AllowLeadingSign = 4
| AllowTrailingSign = 8
| AllowParentheses = 16
| AllowDecimalPoint = 32
| AllowThousands = 64
| AllowExponent = 128
| AllowCurrencySymbol = 256
...
field Globalization.NumberStyles.AllowHexSpecifier: Globalization.NumberStyles = 512
val ofSeq : source:seq<'T> -> 'T []
val keyToWif : key:string -> String
https://en.bitcoin.it/wiki/Wallet_import_format
val key : string
val sha : SHA256Managed
Multiple items
type SHA256Managed =
inherit SHA256
new : unit -> SHA256Managed
member Initialize : unit -> unit
--------------------
SHA256Managed() : SHA256Managed
val extended : byte []
val hashCheck : byte []
val append : array1:'T [] -> array2:'T [] -> 'T []
val rev : array:'T [] -> 'T []
val privateKey : unit -> String
Generates random HEX-string
val chars : char []
val length : int
val data : byte []
val zeroCreate : count:int -> 'T []
val provider : RNGCryptoServiceProvider
Multiple items
type RNGCryptoServiceProvider =
inherit RandomNumberGenerator
new : unit -> RNGCryptoServiceProvider + 3 overloads
member GetBytes : data:byte[] -> unit + 2 overloads
member GetNonZeroBytes : data:byte[] -> unit + 1 overload
--------------------
RNGCryptoServiceProvider() : RNGCryptoServiceProvider
RNGCryptoServiceProvider(str: string) : RNGCryptoServiceProvider
RNGCryptoServiceProvider(rgb: byte []) : RNGCryptoServiceProvider
RNGCryptoServiceProvider(cspParams: CspParameters) : RNGCryptoServiceProvider
val random : char []
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []
val b : byte
More information