7 people like it.

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

Full name: BtcTesting.base58encode


 https://en.bitcoin.it/wiki/Base58Check_encoding
val hash : byte []
Multiple items
val byte : value:'T -> byte (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.byte

--------------------
type byte = Byte

Full name: Microsoft.FSharp.Core.byte
val code_string : char []
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val toArray : list:'T list -> 'T []

Full name: Microsoft.FSharp.Collections.List.toArray
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
  ...

Full name: System.Array
val toList : array:'T [] -> 'T list

Full name: Microsoft.FSharp.Collections.Array.toList
val toBigInt : (byte list * Numerics.BigInteger -> Numerics.BigInteger)
val acc : Numerics.BigInteger
val h : byte
val t : byte list
type bigint = Numerics.BigInteger

Full name: Microsoft.FSharp.Core.bigint
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.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

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
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

Full name: Microsoft.FSharp.Core.char
Ref.contents: Numerics.BigInteger
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 + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
val fromHex : s:string -> byte []

Full name: BtcTesting.fromHex


 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

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
module Seq

from Microsoft.FSharp.Collections
val windowed : windowSize:int -> source:seq<'T> -> seq<'T []>

Full name: Microsoft.FSharp.Collections.Seq.windowed
val mapi : mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.mapi
val i : int
val j : char []
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
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
    static val MaxValue : byte
    static val MinValue : byte
    static member Parse : s:string -> byte + 3 overloads
    static member TryParse : s:string * result:byte -> bool + 1 overload
  end

Full name: System.Byte
Byte.Parse(s: string) : byte
Byte.Parse(s: string, provider: IFormatProvider) : byte
Byte.Parse(s: string, style: Globalization.NumberStyles) : 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
  ...

Full name: System.Globalization.NumberStyles
field Globalization.NumberStyles.AllowHexSpecifier = 512
val ofSeq : source:seq<'T> -> 'T []

Full name: Microsoft.FSharp.Collections.Array.ofSeq
val keyToWif : key:string -> String

Full name: BtcTesting.keyToWif


 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

Full name: System.Security.Cryptography.SHA256Managed

--------------------
SHA256Managed() : unit
val extended : byte []
val hashCheck : byte []
HashAlgorithm.ComputeHash(buffer: byte []) : byte []
HashAlgorithm.ComputeHash(inputStream: IO.Stream) : byte []
HashAlgorithm.ComputeHash(buffer: byte [], offset: int, count: int) : byte []
val append : array1:'T [] -> array2:'T [] -> 'T []

Full name: Microsoft.FSharp.Collections.Array.append
val rev : array:'T [] -> 'T []

Full name: Microsoft.FSharp.Collections.Array.rev
val privateKey : unit -> String

Full name: BtcTesting.privateKey


 Generates random HEX-string
val chars : char []
val length : int
property Array.Length: int
val data : byte []
val zeroCreate : count:int -> 'T []

Full name: Microsoft.FSharp.Collections.Array.zeroCreate
val provider : RNGCryptoServiceProvider
Multiple items
type RNGCryptoServiceProvider =
  inherit RandomNumberGenerator
  new : unit -> RNGCryptoServiceProvider + 3 overloads
  member GetBytes : data:byte[] -> unit
  member GetNonZeroBytes : data:byte[] -> unit

Full name: System.Security.Cryptography.RNGCryptoServiceProvider

--------------------
RNGCryptoServiceProvider() : unit
RNGCryptoServiceProvider(str: string) : unit
RNGCryptoServiceProvider(rgb: byte []) : unit
RNGCryptoServiceProvider(cspParams: CspParameters) : unit
RNGCryptoServiceProvider.GetNonZeroBytes(data: byte []) : unit
val random : char []
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val b : byte

More information

Link:http://fssnip.net/m6
Posted:2 years ago
Author:Tuomas Hietanen
Tags: base58check , btc