Skip to content

Instantly share code, notes, and snippets.

@dhimmel
Last active January 29, 2018 19:14
Show Gist options
  • Save dhimmel/809c3e3a3bd4d6d637a0b4aa1a062dae to your computer and use it in GitHub Desktop.
Save dhimmel/809c3e3a3bd4d6d637a0b4aa1a062dae to your computer and use it in GitHub Desktop.
Using Bitcoin to randomly determine a future outcome involving untrusted parties
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Using Bitcoin to randomly determine a future outcome involving untrusted parties.\n",
"\n",
"This notebook shows how to use Bitcoin as a cryptographic beacon for randomly generating a probability. In short, it converts a Bitcoin block height to a random number between 0 and 1. The envisioned usage is for mutliple parties to agree to a future block height and a theshold.\n",
"\n",
"For example, Daniel and Meredith agree to a threshold (20%) and a future block height ([496710](https://live.blockcypher.com/btc/block/000000000000000000942eab6f4fc2399609abdbef6ae6d522176ed33fde8054/)). If the beacon probability (calculated from the previousely specified block) is less than or equal the 20%, Daniel and Meredith agree to a certain outcome. After block 496710 is mined (and buried by additional blocks for security), anyone can rerun this notebook to see whether the beacon probability is within the threshold and verify the agreed-upon outcome accordingly. In this example, the beacon probability of 77% exceeded 20%, so the agreement did not activate.\n",
"\n",
"This example assumes a binary outcome, however any application that requires a random number is feasible. For more information on the security and reliability of this method, see the study titled \"[On Bitcoin as a public randomness source](https://eprint.iacr.org/2015/1015.pdf)\" and this [related video](https://www.coursera.org/learn/cryptocurrency/lecture/0IDbs/bitcoin-as-randomness-source). In short, it's vulnerable if any party controls substantial mining power.\n",
"\n",
"Created by Daniel Himmelstein and released under the [CC0](https://creativecommons.org/publicdomain/zero/1.0/) public domain dedicaiton.\n",
"\n",
"Requires Python 3.6+ and the `requests` package."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import hashlib\n",
"\n",
"import requests"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Define helper functions"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def get_block_info(height):\n",
" \"\"\"\n",
" Return the block info for a Bitcoin block of a given height using\n",
" the BlockCypher API. If security is a concern, ensure the block is\n",
" sufficient buried that it's unlikely to get orphaned. Also consider\n",
" retreiving the block hash from a personal full node.\n",
" \"\"\"\n",
" url = f'https://api.blockcypher.com/v1/btc/main/blocks/{height}'\n",
" response = requests.get(url)\n",
" block = response.json()\n",
" return block\n",
"\n",
"\n",
"def bytes_to_probability(input_bytes):\n",
" \"\"\"\n",
" Convert bytes to a float between 0 and 1 (0.0 <= probability < 1.0).\n",
" \"\"\"\n",
" input_int = int.from_bytes(input_bytes, 'big')\n",
" max_int = 2 ** (8 * len(input_bytes))\n",
" probability = input_int / max_int\n",
" return probability\n",
"\n",
"\n",
"def hex_to_probability(hex_str, hash_input=False):\n",
" \"\"\"\n",
" Convert a string of hex-encoded bytes to a probability.\n",
" Set hash_input to True to first blake2b hash the input.\n",
" This is useful when the input bytes are not random, for\n",
" example with Bitcoin block hashes which contain leading\n",
" zeros.\n",
" \"\"\"\n",
" bytes_input = bytes.fromhex(hex_str)\n",
" if hash_input:\n",
" bytes_input = hashlib.blake2b(bytes_input).digest()\n",
" return bytes_to_probability(bytes_input)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Perform analysis"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# Set your block height\n",
"block_height = 496710\n",
"threshold = 0.2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bitcoin block 496710\n",
"Block Hash: 000000000000000000942eab6f4fc2399609abdbef6ae6d522176ed33fde8054\n",
"Block Time: 2017-11-29T15:38:51Z\n",
"Probability: 77.018%\n",
"Outcome activates (i.e. is 77.0% ≤ 20.0%): False\n"
]
}
],
"source": [
"# Retrieve block hash\n",
"block = get_block_info(block_height)\n",
"block_hash = block['hash']\n",
"# Pass the block hash through extractor function to get probability\n",
"probability = hex_to_probability(block_hash, hash_input=True)\n",
"outcome = probability <= threshold\n",
"# Print information\n",
"print(f'''\\\n",
"Bitcoin block {block_height}\n",
"Block Hash: {block_hash}\n",
"Block Time: {block['time']}\n",
"Probability: {probability:.3%}\n",
"Outcome activates (i.e. is {probability:.1%} ≤ {threshold:.1%}): {outcome}\\\n",
"'''\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python [default]",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@dhimmel
Copy link
Author

dhimmel commented Nov 29, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment