17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/experimental/script_abstraction.mli:
--------------------------------------------------------------------------------
1 | type ScriptKey =
2 | | ScriptPubKey of string
3 | | PubKey of string
4 | | Address of string
5 |
6 |
7 | type ScriptAbstraction =
8 | | P2PKH of ScriptKey
9 | | P2WPKH of ScriptKey
10 | | P2SH of ScriptKey
11 | | P2WSH of ScriptKey
12 | | P2PK of ScriptKey
13 | | Nulldata of string
14 | | Multisig of int * PubKey list
15 | | AbsoluteTimelock of Script.t * ScriptAbstraction
16 | | RelativeTimelock of Script.t * ScriptAbstraction
17 | | IfElse of ScriptAbstraction * ScriptAbstraction
18 | | Hashlock256 of Script.t * ScriptPubKey
19 | | Hashlock160 of Script.t * ScriptPubKey
--------------------------------------------------------------------------------
/src/script_nulldata.ml:
--------------------------------------------------------------------------------
1 | open Script;;
2 |
3 | module Input = Script_template.EmptyInput;;
4 |
5 | module Output = struct
6 | type t = Script.data;;
7 | let name = "nulldata";;
8 |
9 | let check s =
10 | match fst s with
11 | | OP_RETURN (data) :: [] -> true
12 | | _ -> false
13 | ;;
14 |
15 | let encode data = Script.of_opcodes [ OP_RETURN (data) ];;
16 |
17 | let decode s =
18 | match fst s with
19 | | OP_RETURN (data) :: [] -> data
20 | | _ -> ""
21 | ;;
22 |
23 | let spendable_by s prefix = "";;
24 | end
25 |
26 |
27 | module Script_nulldata = Script_template.Make_template (Input) (Output);;
--------------------------------------------------------------------------------
/src/varint.mli:
--------------------------------------------------------------------------------
1 | (** A VarInt (variable integer) is a field used in transaction data to indicate the number
2 | of upcoming fields, or the length of an upcoming field. *)
3 | open Stdint
4 |
5 | val parse_varint : Bitstring.t -> Uint64.t * Bitstring.t
6 | (** [parse_varint bits] parse Bitstring [bits] returing the Uint64.t value and the rest
7 | of the bitstring *)
8 |
9 | val bitstring_of_varint : Int64.t -> Bitstring.t
10 | (** [bitstring_of_varint num] encodes [num] to its bitstring varint representation *)
11 |
12 | val encoding_length : Uint64.t -> int
13 | (** [encoding_length num] returns the length of [num] if encoded as varint *)
14 |
--------------------------------------------------------------------------------
/test/proto_test.ml:
--------------------------------------------------------------------------------
1 | open Bitcoinml;;
2 | open Stdint;;
3 | open OUnit2;;
4 | open Hex;;
5 |
6 | (*
7 | let parse_test prefix pub addr octx =
8 | assert_equal addr @@ Address.of_pubhash prefix (Hex.to_string pub)
9 | ;;
10 |
11 | let serialize_test msg octx =
12 | let ad = Proto.serialize msg in
13 | assert_equal address @@ ad
14 | ;;
15 | *)
16 |
17 | let tlist = [
18 | (*"proto.parse" >:: address_of_pubhash_test 0x05 (`Hex "010966776006953D5567439E5E39F86A0D273BEE") "31nVrspaydBz8aMpxH9WkS2DuhgqS1fCuG";
19 | "proto.serialize" >:: address_of_pubhash_test 0x00 (`Hex "010966776006953D5567439E5E39F86A0D273BEE") "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM";
20 | *)
21 | ];;
--------------------------------------------------------------------------------
/src/script_multisig.ml:
--------------------------------------------------------------------------------
1 | open Script;;
2 |
3 | let op_int_base = Script.opcode_to_hex OP_RESERVED;;
4 |
5 | module Input = struct
6 | type t = int;;
7 | let check v = true;;
8 | let encode v = Script.empty;;
9 | let decode v = 0;;
10 | end
11 |
12 | module Output = struct
13 | type t = {
14 | m: int;
15 | pubkeys: string list;
16 | };;
17 | let name = "p2ms";;
18 |
19 | let check v = true;;
20 |
21 | let encode v = Script.of_opcodes [ OP_CHECKMULTISIG ];;
22 |
23 | let decode s = {
24 | m= 0;
25 | pubkeys= []
26 | };;
27 |
28 | let spendable_by s prefix = "";;
29 | end
30 |
31 |
32 | module Script_multisig = Script_template.Make_template (Script_template.EmptyInput) (Output);;
33 |
--------------------------------------------------------------------------------
/src/script_template.ml:
--------------------------------------------------------------------------------
1 |
2 | module EmptyInput = struct
3 | type t = string;;
4 | let check v = false;;
5 | let encode v = Script.empty;;
6 | let decode v = "";;
7 | end
8 |
9 |
10 | module type Output = sig
11 | type t
12 |
13 | val name: string
14 | val encode: t -> Script.t
15 | val decode: Script.t -> t
16 | val check: Script.t -> bool
17 | val spendable_by: Script.t -> Address.prefix -> Address.t
18 | end
19 |
20 | module type Input = sig
21 | type t
22 |
23 | val encode: t -> Script.t
24 | val decode: Script.t -> t
25 | val check: Script.t -> bool
26 | end
27 |
28 |
29 | module Make_template (ITemplate: Input) (OTemplate: Output) = struct
30 | type t_inp = ITemplate;;
31 | type t_out = OTemplate;;
32 |
33 | let input = ITemplate;;
34 | let output = OTemplate;;
35 | end
36 |
--------------------------------------------------------------------------------
/src/script_witnessscripthash.ml:
--------------------------------------------------------------------------------
1 | open Script;;
2 | open Address;;
3 |
4 | module Input = struct
5 | type t = int;;
6 | let check v = true;;
7 | let encode v = Script.empty;;
8 | let decode v = 0;;
9 | end
10 |
11 | module Output = struct
12 | type t = string;;
13 | let name = "p2wsh";;
14 |
15 | let check s =
16 | match fst s with
17 | | OP_0 :: OP_DATA (32, wsh) :: [] -> true
18 | | _ -> false
19 | ;;
20 |
21 | let encode wsh = Script.of_opcodes [ OP_0; OP_DATA (32, wsh) ];;
22 |
23 | let decode s =
24 | match fst s with
25 | | OP_0 :: OP_DATA (32, wsh) :: [] -> wsh
26 | | _ -> ""
27 | ;;
28 |
29 | let spendable_by s prefix = decode s |> Address.of_witness prefix.hrp 0x00;;
30 | end
31 |
32 |
33 | module Script_witnessscripthash = Script_template.Make_template (Input) (Output);;
--------------------------------------------------------------------------------
/src/script_witnesspubkeyhash.ml:
--------------------------------------------------------------------------------
1 | open Script;;
2 | open Address;;
3 |
4 |
5 | module Input = struct
6 | type t = int;;
7 | let check v = true;;
8 | let encode v = Script.empty;;
9 | let decode v = 0;;
10 | end
11 |
12 | module Output = struct
13 | type t = string;;
14 | let name = "p2wpkh";;
15 |
16 | let check s =
17 | match fst s with
18 | | OP_0 :: OP_DATA (20, wpkh) :: [] -> true
19 | | _ -> false
20 | ;;
21 |
22 | let encode pkh = Script.of_opcodes [ OP_0; OP_DATA (20, pkh) ];;
23 |
24 | let decode s =
25 | match fst s with
26 | | OP_0 :: OP_DATA (20, wpkh) :: [] -> wpkh
27 | | _ -> ""
28 | ;;
29 |
30 | let spendable_by s prefix = decode s |> Address.of_witness prefix.hrp 0x00;;
31 | end
32 |
33 | module Script_witnesspubkeyhash = Script_template.Make_template (Input) (Output);;
--------------------------------------------------------------------------------
/src/script_scripthash.ml:
--------------------------------------------------------------------------------
1 | open Script;;
2 | open Address;;
3 |
4 | module Input = struct
5 | type t = int;;
6 | let check v = true;;
7 | let encode v = Script.empty;;
8 | let decode v = 0;;
9 | end
10 |
11 | module Output = struct
12 | type t = string;;
13 | let name = "p2sh";;
14 |
15 | let check s =
16 | match fst s with
17 | | OP_HASH160 :: OP_DATA (20, sh) :: OP_EQUAL :: [] -> true
18 | | _ -> false
19 | ;;
20 |
21 | let encode sh = Script.of_opcodes [ OP_HASH160; OP_DATA (20, sh); OP_EQUAL ];;
22 |
23 | let decode s =
24 | match fst s with
25 | | OP_HASH160 :: OP_DATA (20, sh) :: OP_EQUAL :: [] -> sh
26 | | _ -> ""
27 | ;;
28 |
29 | let spendable_by s prefix = decode s |> Address.of_pubhash prefix.scripthash;;
30 | end
31 |
32 |
33 | module Script_scripthash = Script_template.Make_template (Input) (Output);;
--------------------------------------------------------------------------------
/src/params.mli:
--------------------------------------------------------------------------------
1 | (** Params handles different protocol parameters for different Bitcoin based blockchains *)
2 |
3 | open Stdint
4 | type e = BTC | XTN | BCH | LTC | LTN | SIDECHAIN | NOTFOUND
5 |
6 | type t = {
7 | hash_function : string -> string;
8 | block_size : int;
9 | block_time : int;
10 | genesis : Block.Header.t;
11 | magic : int;
12 | port : int;
13 | seeds : string list;
14 | network : e;
15 | checkpoints : (int * Hash.t) list;
16 | prefixes : Address.prefix;
17 | max_money : Int64.t;
18 | }
19 |
20 | val of_network : e -> t
21 | (** [of_network e] returns the params of the [e] network *)
22 |
23 | val name_of_network : e -> string
24 | (** [name_of_network e] returns the readable name of the [e] network *)
25 |
26 | val abbr_to_network : string -> e
27 | (** [abbr_to_network ab] returns the network of a readable abbreviation *)
28 |
--------------------------------------------------------------------------------
/src/base58.ml:
--------------------------------------------------------------------------------
1 | open Big_int;;
2 |
3 | let bitcoin_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";;
4 | let big_base = big_int_of_int 58;;
5 |
6 | let encode_check data =
7 | let string_to_bigint data =
8 | let rec btb data acc = match String.length data with
9 | | 0 -> acc
10 | | n ->
11 | let c' = String.get data 0 |> Char.code in
12 | let rest = String.sub data 1 (n - 1) in
13 | btb rest @@ add_int_big_int c' (mult_int_big_int 0x100 acc)
14 | in btb data zero_big_int
15 | in
16 | let rec encode x =
17 | match eq_big_int x zero_big_int with
18 | | true -> if (String.get data 0 |> Char.code) = 0x00 then "1" else ""
19 | | false ->
20 | let (q, index) = quomod_big_int x big_base in
21 | let ch = String.make 1 bitcoin_alphabet.[int_of_big_int index] in
22 | (encode q) ^ ch
23 | in encode @@ string_to_bigint data
24 | ;;
25 |
26 |
--------------------------------------------------------------------------------
/docs/bitcoinml/index.html:
--------------------------------------------------------------------------------
1 |
2 | index (bitcoinml.index)
bitcoinml index
Library bitcoinml
The entry point of this library is the module: Bitcoinml.
--------------------------------------------------------------------------------
/src/block_lazy.mli:
--------------------------------------------------------------------------------
1 | (** Block_lazy is a special representation of Block, where only the header is parsed leaving the
2 | transactions data unparsed until the Lazy is forced *)
3 |
4 | type t = {
5 | header : Block.Header.t;
6 | ltxs : Tx.t list option Lazy.t;
7 | size : int
8 | }
9 |
10 | val parse : ?hex:bool -> string -> t option
11 | (** [parse ~hex:bool data] parses the [data] and returns a [t] option; [data] could be
12 | a binary data, or an hex human readable string if [~hex] is true *)
13 |
14 | val parse_legacy : ?hex:bool -> string -> t option
15 | (** [parse_legacy ~hex:bool data]; same as [parse] but disable segwit *)
16 |
17 | val force : t -> Block.t option
18 | (** [force lblock] forces the parsing of a lazy block [lblock], returning a [Block.t] option *)
19 |
20 | val force_option : t option -> Block.t option
21 | (** [force_option lblock]; same as [force] but receive an option [t] as parameter *)
22 |
--------------------------------------------------------------------------------
/docs/bitcoinml/Bitcoinml__Base58/index.html:
--------------------------------------------------------------------------------
1 |
2 | Bitcoinml__Base58 (bitcoinml.Bitcoinml__Base58)
--------------------------------------------------------------------------------
/src/script_pubkey.ml:
--------------------------------------------------------------------------------
1 | open Script;;
2 | open Address;;
3 |
4 | module Input = struct
5 | type t = Script.data;;
6 | let check v = (* TODO check if it's a canonical DER signaure (bip66) *) true;;
7 | let encode v = Script.of_opcodes [OP_DATA (String.length v, v)];;
8 |
9 | let decode v =
10 | match fst v with
11 | | [OP_DATA (n, v)] -> v
12 | | _ -> ""
13 | end
14 |
15 |
16 | module Output = struct
17 | type t = string;;
18 | let name = "p2pk";;
19 |
20 | let check s =
21 | match fst s with
22 | | OP_DATA (n, pk) :: OP_CHECKSIG :: [] when n = 33 || n = 65 -> true
23 | | _ -> false
24 | ;;
25 |
26 | let encode pk = Script.of_opcodes [OP_DATA (String.length pk, pk); OP_CHECKSIG];;
27 |
28 | let decode s =
29 | match fst s with
30 | | OP_DATA (n, pk) :: OP_CHECKSIG :: [] when n = 33 || n = 65 -> pk
31 | | _ -> ""
32 | ;;
33 |
34 | let spendable_by s prefix = decode s |> Address.of_pub prefix.pubkeyhash;;
35 | end
36 |
37 |
38 | module Script_pubkey = Script_template.Make_template (Input) (Output);;
--------------------------------------------------------------------------------
/src/address.mli:
--------------------------------------------------------------------------------
1 | (** An address is an almost readable representation of Bitcoin wallet identifier *)
2 |
3 | type prefix = {
4 | pubkeyhash: int;
5 | scripthash: int;
6 | hrp: string;
7 | }
8 | (** Address prefixes structure *)
9 |
10 | type t = string
11 | (** Address abstract type *)
12 |
13 | (** Handle segwit native bech32 addresses *)
14 | module Bech32 : sig
15 | val encode : string -> int -> string -> t
16 | (** [encode hrp witver witprog] encodes [witprog] in bech32 address given the [hrp] and the
17 | [witver] witness version *)
18 | end
19 |
20 |
21 | val of_pub : int -> string -> t
22 | (** [of_pub prefix pk] encodes the address from a public key [pk] given the network prefix [prefix] *)
23 |
24 | val of_pubhash : int -> string -> t
25 | (** [of_pubhash prefix pkh] encodes the address from a public key hash [pkh] given the network
26 | prefix [prefix] *)
27 |
28 | val of_witness : string -> int -> string -> t
29 | (** [of_witness hrp witver witprog] encodes [witprog] in bech32 address given the [hrp] and the
30 | [witver] witness version *)
--------------------------------------------------------------------------------
/src/script_verify.mli:
--------------------------------------------------------------------------------
1 | (** Verification of Bitcoin scripts *)
2 |
3 | (** Abstract module for verify functions *)
4 | module Sigver : sig
5 | type t = string -> string -> bool
6 | end
7 |
8 | (** Script execution stack *)
9 | module SStack : sig
10 | type t = int Stack.t
11 |
12 | val create : unit -> t
13 | val pop : t -> int
14 | val top : t -> int
15 | val push : int -> t -> unit
16 | val push_data : string -> t -> unit
17 | end
18 |
19 | val verify : Sigver.t -> Script.t -> Script.t -> bool
20 | (** [verify sigver s1 s2] execute a script [s1] and [s2] using [sigver] *)
21 |
22 | val is_spendable : Script.t -> bool
23 | (** [is_spendable s] returns true if [s] is spendable by a recognized address *)
24 |
25 | val spendable_by : Script.t -> Address.prefix -> string option
26 | (** [spendable_by s prefix] returns the address (using [prefix]) which is able to
27 | spend the given script *)
28 |
29 |
30 | val classify_output : Script.t -> string
31 | (** [classify_output s] returns the template name of the output script [s] if any *)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016-2020 Davide Gessa
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/src/script_witnesscommitment.ml:
--------------------------------------------------------------------------------
1 | open Script;;
2 | open Address;;
3 | open Bitstring;;
4 |
5 |
6 | module Output = struct
7 | type t = Hash.t;;
8 | let name = "wcommitment";;
9 |
10 | let encode wc =
11 | Script.of_opcodes [ OP_RETURN (string_of_bitstring [%bitstring {|
12 | 0x24 : 1*8 : littleendian;
13 | (Hex.to_string (`Hex "aa21a9ed")) : 4*8 : string;
14 | wc : 32 * 8 : string
15 | |}] ) ]
16 | ;;
17 |
18 | let decode s =
19 | match fst s with
20 | | OP_RETURN (data) :: [] when String.length data >= 38 -> (
21 | match%bitstring (bitstring_of_string data) with
22 | | {|
23 | p24 : 1*8 : littleendian;
24 | header : 4*8 : string;
25 | hash : 4*8 : string;
26 | rest : -1 : bitstring
27 | |} ->
28 | if p24 <> 0x24 then ""
29 | else if "aa21a9ed" <> (Hex.of_string header |> Hex.show) then ""
30 | else Hash.of_bin hash)
31 | | _ -> ""
32 | ;;
33 |
34 | let check s = decode s <> "";;
35 |
36 | let spendable_by s prefix = "";;
37 | end
38 |
39 | module Script_witnesspubkeyhash = Script_template.Make_template (Script_template.EmptyInput) (Output);;
--------------------------------------------------------------------------------
/docs/bitcoinml/Bitcoinml__Address/Bech32/index.html:
--------------------------------------------------------------------------------
1 |
2 | Bech32 (bitcoinml.Bitcoinml__Address.Bech32)
encode hrp witver witprog encodes witprog in bech32 address given the hrp and the witver witness version
--------------------------------------------------------------------------------
/src/experimental/simplicity.ml:
--------------------------------------------------------------------------------
1 | type t =
2 | | Unit
3 | | Iden
4 | | Take of t
5 | | Drop of t
6 | | Injl of t
7 | | Injr of t
8 | | Comp of t * t
9 | | Case of t * t
10 | | Pair of t * t
11 | | Sum of t * t
12 | ;;
13 |
14 |
15 | module Examples = struct
16 | let two = Sum (Unit, Unit);;
17 | let not = Comp (
18 | (Pair (Iden, Unit)),
19 | (Case (Injr Unit, Injl Unit))
20 | );;
21 |
22 | let halfadder = Case (
23 | Drop (Pair (Injl (Unit), Iden)),
24 | Drop (Pair (Iden, not))
25 | );;
26 |
27 | let fulladder1 =
28 | Comp (
29 | Pair (Take halfadder, Drop Iden),
30 | Comp (
31 | Pair (
32 | Take (Take Iden),
33 | Comp (
34 | Pair (Take (Drop Iden), Drop Iden),
35 | halfadder
36 | )
37 | ),
38 | Pair (
39 | Case (Injr Unit, Drop (Take Iden)),
40 | Drop (Drop Iden)
41 | )
42 | )
43 | )
44 | ;;
45 | end
46 |
47 | (*let rec eval e = match e with
48 | | Iden -> fun x -> x
49 | | Comp (s, t) -> fun x -> eval t (eval s x)
50 | | Injl (t) -> fun x -> fst (eval t x)
51 | | Injr (t) -> fun x -> snd (eval t x)
52 | | Pair (s, t) -> fun x -> (eval s x, eval t x)
53 | ;;*)
54 |
55 |
--------------------------------------------------------------------------------
/docs/bitcoinml/Bitcoinml__Script_witnesscommitment/index.html:
--------------------------------------------------------------------------------
1 |
2 | Bitcoinml__Script_witnesscommitment (bitcoinml.Bitcoinml__Script_witnesscommitment)
--------------------------------------------------------------------------------
/src/hash.mli:
--------------------------------------------------------------------------------
1 | (** An hash is a 32B binary string, represented in human readable hex encoded 64B string *)
2 |
3 | type t = string
4 | type hash = t
5 | type b = string
6 |
7 | val reverse : string -> string
8 | (** [reverse s] reverses the string [s] *)
9 |
10 | val to_bin : t -> b
11 | (** [to_bin h] transforms [h] in binary format *)
12 |
13 | val to_bin_norev : t -> b
14 | (** [to_bin_norev h] transforms [h] in binary format without reversing *)
15 |
16 | val to_bigint : t -> Big_int.big_int
17 | (** [to_bigint h] transforms [h] in a [Big_int] *)
18 |
19 | val of_bin : b -> t
20 | (** [of_bin data] transforms [data] in an hash *)
21 |
22 | val of_bin_norev : b -> t
23 | (** [of_bin_norev data] transforms [data] in an hash without reversing *)
24 |
25 | val zero : t
26 | (** [zero] hash with only zeros *)
27 |
28 |
29 |
30 | val sha1 : t -> t
31 | (** [sha1 data] returns the sha1 of [data] *)
32 |
33 | val sha256 : t -> t
34 | (** [sha256 data] returns the sha2 of [data] *)
35 |
36 | val ripemd160 : t -> t
37 | (** [ripemd160 data] returns the ripedm160 of [data] *)
38 |
39 | val hash160 : t -> t
40 | (** [hash160 data] returns the hash160 of [data] *)
41 |
42 | val hash256 : t -> t
43 | (** [hash256 data] returns the hash256 of [data] *)
44 |
45 | val dsha256 : t -> t
46 | (** [dsha256 data] returns the double sha2 of [data] *)
47 |
48 | val checksum4 : t -> t
49 | (** [checksum4 data] returns the checksum4 of [data] *)
50 |
--------------------------------------------------------------------------------
/docs/bitcoinml/Bitcoinml__Script_nulldata/index.html:
--------------------------------------------------------------------------------
1 |
2 | Bitcoinml__Script_nulldata (bitcoinml.Bitcoinml__Script_nulldata)