remove salt from the name registration process

This commit is contained in:
Ryan Shea
2015-02-12 16:32:00 -05:00
parent bc21563b83
commit cfc077b180
13 changed files with 65 additions and 114 deletions

View File

@@ -20,8 +20,6 @@ __Table of Contents__
- [Constraints](<#constraints>)
## Intro
<a name="intro"/>
@@ -56,7 +54,7 @@ Install libzmq-dev
+ validated sequence of operations + rules to interpret them = global consensus / agreed upon view of the system
+ data is simply stored in the blockchain in a defined sequence, and nodes read the blockchain and interpret the sequence of events with a set of defined rules. From this, they build a view of the system that should be in sync.
register names by being the first to include the name in a “registration” operation
+ to prevent people from stealing your name, first secretly “preorder” the name, but include a salted hash of the name in the blockchain
+ to prevent people from stealing your name, first secretly “preorder” the name, but include a hash of the name in the blockchain
+ to associate data with the name, issue an “update” operation by including a hash of the data and storing the data itself in the DHT
+ to lookup the data associated with a name, issue a request to an opennamed node, which will lookup the names entry in the nameset, find the hash associated with the name, then go into the DHT with the hash and get the data associated with it
+ there are many, many possible namespaces
@@ -84,8 +82,7 @@ register names by being the first to include the name in a “registration” op
- `nameset`: all the names ever registered on all possible namespaces
- `hash160`: a 20-byte ripemd160 hash
- `salt`: a random value appended to data in order to prevent reverse-lookups of the hashed data
- `preorder hash`: a hash160 of a given name to preorder, a random salt, and the scriptPubKey of the registrant
- `preorder hash`: a hash160 of a given name to preorder and the scriptPubKey of the registrant
- `name encoding`: a given name converted from base 40 to base 256
- `consensus hash`: a hash of a data string generated from a representation of the nameset (also known as the historical record hash or merkle snapshot)
- `update hash`: a hash of the data to be associated with a given name

View File

@@ -9,4 +9,4 @@
__version__ = '0.1.0'
from .opennamed import run_opennamed
from .openname_cli import run_cli
from .openname_cli import run_cli

View File

@@ -7,6 +7,8 @@ from opennamed import bitcoind
def refresh_index(first_block, last_block):
"""
"""
start = datetime.datetime.now()
@@ -30,7 +32,7 @@ def refresh_index(first_block, last_block):
print "merkle snapshot: %s\n" % merkle_snapshot
pprint(db.name_records)
fout = open('lastblock.txt','w') #to overwrite
fout = open('lastblock.txt', 'w') # to overwrite
fout.write(str(last_block))
fout.close()

View File

@@ -133,18 +133,18 @@ LENGTHS = {
'opcode': 1,
'name_hash': 20,
'consensus_hash': 16,
'namelen': 1,
'name_min': 1,
'name_max': 16,
'unencoded_name': 24,
'salt': 16,
'update_hash': 20,
}
MIN_OP_LENGTHS = {
'preorder': LENGTHS['name_hash'],
'registration': LENGTHS['name_min'] + LENGTHS['salt'],
'update': LENGTHS['name_min'] + LENGTHS['update_hash'],
'transfer': LENGTHS['name_min']
'registration': LENGTHS['namelen'] + LENGTHS['name_min'],
'update': LENGTHS['namelen'] + LENGTHS['name_min'] + LENGTHS['update_hash'],
'transfer': LENGTHS['namelen'] + LENGTHS['name_min']
}
OP_RETURN_MAX_SIZE = 40

View File

@@ -7,23 +7,10 @@ from .b40 import b40_to_bin
from .config import LENGTHS
def gen_name_salt(hex_format=False):
bin_salt = dev_urandom_entropy(LENGTHS['salt'])
return bin_salt
def is_hex_salt(s):
if is_hex(s) and len(unhexlify(s)) == LENGTHS['salt']:
return True
return False
def hash_name(name, salt, script_pubkey, hex_format=True):
if hex_format and not (is_hex_salt(salt) and is_hex(script_pubkey)):
raise ValueError('Salt must be a %i byte hex string' % LENGTHS['salt'])
def hash_name(name, script_pubkey):
bin_name = b40_to_bin(name)
salted_name = bin_name + unhexlify(salt) + unhexlify(script_pubkey)
return hex_hash160(salted_name)
name_and_pubkey = bin_name + unhexlify(script_pubkey)
return hex_hash160(name_and_pubkey)
def calculate_consensus_hash128(consensus_hash):

View File

@@ -19,9 +19,9 @@ def no_pending_higher_priority_registration(db, name, mining_fee):
return True
def has_preordered_name(db, name, salt, sender_script_pubkey):
def has_preordered_name(db, name, sender_script_pubkey):
try:
name_hash = hash_name(name, salt, sender_script_pubkey)
name_hash = hash_name(name, sender_script_pubkey)
except ValueError:
return False

View File

@@ -1,9 +1,9 @@
from ..hashing import hash_name
def remove_preorder(db, name, salt, script_pubkey):
def remove_preorder(db, name, script_pubkey):
try:
name_hash = hash_name(name, salt, script_pubkey)
name_hash = hash_name(name, script_pubkey)
except ValueError:
return False
else:
@@ -17,7 +17,7 @@ def commit_preorder(db, nameop):
def commit_registration(db, nameop, current_block_number):
name = nameop['name']
remove_preorder(db, name, nameop['salt'], nameop['sender'])
remove_preorder(db, name, nameop['sender'])
db.name_records[name] = {
'value_hash': None,
'owner': str(nameop['sender']),

View File

@@ -9,7 +9,7 @@ def log_registration(db, nameop):
name = nameop['name']
# check if this registration is a valid one
if (name_not_registered(db, name)
and has_preordered_name(db, name, nameop['salt'], nameop['sender'])
and has_preordered_name(db, name, nameop['sender'])
and is_mining_fee_sufficient(name, nameop['fee'])):
# we're good - log the registration!
db.pending_registrations[name].append(nameop)

View File

@@ -6,41 +6,35 @@ from binascii import hexlify, unhexlify
from ..b40 import b40_to_hex
from ..config import *
from ..scripts import name_script_to_hex, add_magic_bytes
from ..hashing import hash_name, calculate_consensus_hash128, gen_name_salt
from ..hashing import hash_name, calculate_consensus_hash128
def build(name, script_pubkey, consensus_hash, salt=None, testset=False):
""" Takes in an ascii string as a name and an optional hex salt.
def build(name, script_pubkey, consensus_hash, testset=False):
""" Takes in an ascii string as a name.
"""
if salt:
if not is_hex(salt) and len(unhexlify(salt)) == LENGTHS['salt']:
raise ValueError('Invalid salt')
else:
salt = hexlify(gen_name_salt())
name_hash = hash_name(name, salt, script_pubkey)
name_hash = hash_name(name, script_pubkey)
script = 'NAME_PREORDER %s %s' % (name_hash, consensus_hash)
hex_script = name_script_to_hex(script)
packaged_script = add_magic_bytes(hex_script, testset=testset)
return packaged_script, salt
return packaged_script
def broadcast(name, consensus_hash, private_key, salt=None,
def broadcast(name, consensus_hash, private_key,
blockchain_client=BlockchainInfoClient(), testset=False):
""" Builds and broadcasts a preorder transaction.
"""
hash160 = BitcoinPrivateKey(private_key).public_key().hash160()
script_pubkey = script_to_hex(
'OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG' % hash160)
nulldata, salt = build(
name, script_pubkey, consensus_hash, testset=testset, salt=salt)
nulldata = build(
name, script_pubkey, consensus_hash, testset=testset)
response = embed_data_in_blockchain(
nulldata, private_key, blockchain_client, format='hex')
# response = {'success': True }
response.update(
{'data': nulldata, 'salt': salt, 'consensus_hash': consensus_hash})
{'data': nulldata, 'consensus_hash': consensus_hash})
return response

View File

@@ -7,24 +7,22 @@ from ..config import *
from ..scripts import name_script_to_hex, add_magic_bytes
def build(name, salt, testset=False):
""" Takes in the name that was preordered, along with the salt used.
def build(name, testset=False):
""" Takes in the name that was preordered.
"""
hex_name = b40_to_hex(name)
name_len = len(hex_name)/2
if not is_hex(salt):
salt = hexlify(salt)
readable_script = 'NAME_REGISTRATION %i %s %s' % (name_len, hex_name, salt)
readable_script = 'NAME_REGISTRATION %i %s' % (name_len, hex_name)
hex_script = name_script_to_hex(readable_script)
packaged_script = add_magic_bytes(hex_script, testset=testset)
return packaged_script
def broadcast(name, salt, private_key,
def broadcast(name, private_key,
blockchain_client=BlockchainInfoClient(), testset=False):
nulldata = build(name, salt, testset=testset)
nulldata = build(name, testset=testset)
# response = {'success': True }
response = embed_data_in_blockchain(
nulldata, private_key, blockchain_client, format='hex')
@@ -35,9 +33,7 @@ def broadcast(name, salt, private_key,
def parse(bin_payload):
name_len = ord(bin_payload[0:1])
name = bin_payload[1:1+name_len]
salt = bin_payload[1+name_len:1+name_len+LENGTHS['salt']]
return {
'opcode': 'NAME_REGISTRATION',
'name': bin_to_b40(name),
'salt': hexlify(salt)
'name': bin_to_b40(name)
}

View File

@@ -107,30 +107,24 @@ def run_cli():
# ------------------------------------
subparser = subparsers.add_parser(
'preorder',
help='<name> <consensushash> <privatekey> | preorder a name')
help='<name> <privatekey> | preorder a name')
subparser.add_argument(
'name', type=str,
help='the name that you want to preorder')
subparser.add_argument(
'consensushash', type=str,
help='the current consensus hash of the nameset')
subparser.add_argument(
'privatekey', type=str,
help='the privatekey of the Bitcoin address that will own the name')
help='the private key of the Bitcoin address that will own the name')
# ------------------------------------
subparser = subparsers.add_parser(
'register',
help='<name> <salt> <privatekey> | register/claim a name')
help='<name> <privatekey> | register/claim a name')
subparser.add_argument(
'name', type=str,
help='the name that you want to register/claim')
subparser.add_argument(
'salt', type=str,
help='the salt')
subparser.add_argument(
'privatekey', type=str,
help='the privatekey of the Bitcoin address that will own the name')
help='the private key of the Bitcoin address that will own the name')
# ------------------------------------
subparser = subparsers.add_parser(
@@ -198,19 +192,16 @@ def run_cli():
client = proxy.callRemote('getinfo')
elif args.action == 'ping':
client = proxy.callRemote('ping')
elif args.action == 'preorder':
logger.debug('Preordering %s', args.name)
client = proxy.callRemote('preorder', args.name, args.consensushash,
args.privatekey)
client = proxy.callRemote('preorder', args.name, args.privatekey)
elif args.action == 'register':
logger.debug('Registering %s', args.name)
client = proxy.callRemote('register', args.name, args.salt,
args.privatekey)
client = proxy.callRemote('register', args.name, args.privatekey)
elif args.action == 'update':
logger.debug('Updating %s', args.name)

View File

@@ -84,6 +84,8 @@ class OpennamedRPC(jsonrpc.JSONRPC):
return self.dht_server.get(key)
def jsonrpc_set(self, key, value):
"""
"""
reply = {}
@@ -104,6 +106,8 @@ class OpennamedRPC(jsonrpc.JSONRPC):
return self.dht_server.set(key, value)
def jsonrpc_getinfo(self):
"""
"""
info = bitcoind.getinfo()
reply = {}
@@ -111,29 +115,32 @@ class OpennamedRPC(jsonrpc.JSONRPC):
reply['test'] = "hello"
return reply
def jsonrpc_preorder(self, name, consensushash, privatekey):
def jsonrpc_preorder(self, name, privatekey):
""" Preorder a name
"""
print str(privatekey)
working_dir = get_working_dir()
namespace_file = os.path.join(
working_dir, config.OPENNAMED_NAMESPACE_FILE)
db = NameDb(namespace_file)
consensus_hash = db.consensus_hashes.get('current')
resp = preorder_name(
name, consensushash, str(privatekey),
blockchain_client=bitcoind_client,
testset=True)
name, consensus_hash, str(privatekey),
blockchain_client=bitcoind_client, testset=True)
log.debug('preorder <%s, %s>' % (name, privatekey))
return resp
def jsonrpc_register(self, name, salt, privatekey):
def jsonrpc_register(self, name, privatekey):
""" Register a name
"""
resp = register_name(name, salt, privatekey,
resp = register_name(name, privatekey,
blockchain_client=bitcoind_client, testset=True)
log.debug('register <%s, %s, %s>' % (name, salt, privatekey))
log.debug('register <%s, %s, %s>' % (name, privatekey))
return resp
@@ -169,6 +176,8 @@ class OpennamedRPC(jsonrpc.JSONRPC):
def refresh_index(first_block, last_block, initial_index=False):
"""
"""
from twisted.python import log as twisted_log
@@ -222,6 +231,8 @@ index_initialized = False
def reindex_blockchain():
"""
"""
from twisted.python import log
global old_block
@@ -252,6 +263,8 @@ def reindex_blockchain():
def get_working_dir():
"""
"""
from os.path import expanduser
home = expanduser("~")
@@ -266,6 +279,8 @@ def get_working_dir():
def get_index_range(start_block=0):
"""
"""
from lib.config import START_BLOCK

View File

@@ -19,7 +19,6 @@ blockchain_client = ChainComClient(
registration_example_1 = {
'name': 'ryanshea',
'salt': '83675d4f5c112b74e86af99b7ec83cec',
'data': """{ }""",
'recipient': '1DuckDmHTXVxSHC7UafaBiUZB81qYhKprF'
}
@@ -34,7 +33,7 @@ class NamePreorderTest(unittest.TestCase):
consensus_hash128 = str(self.namedb.consensus_hashes['current'])
resp = preorder_name(
self.data['name'], consensus_hash128, SECRETS['private_keys'][0],
salt=self.data['salt'], blockchain_client=blockchain_client,
blockchain_client=blockchain_client,
testset=True)
print resp
self.assertTrue('success' in resp)
@@ -49,7 +48,7 @@ class NameRegistrationTest(unittest.TestCase):
def test_name_registration(self):
resp = register_name(
self.data['name'], self.data['salt'], SECRETS['private_keys'][0],
self.data['name'], SECRETS['private_keys'][0],
blockchain_client=blockchain_client, testset=True)
print resp
self.assertTrue('success' in resp)
@@ -108,36 +107,6 @@ class MerkleRootTest(unittest.TestCase):
self.assertEqual(merkle_root, self.merkle_root)
"""class NameOperationSequenceTest(unittest.TestCase):
def setUp(self):
blockchain_client = ChainComClient(
api_key_id=SECRETS['chain_api_id'],
api_key_secret=SECRETS['chain_api_secret'])
self.private_keys = SECRETS['private_keys']
self.data = registration_example_1
def tearDown(self):
pass
def test_name_preorder(self):
resp = preorder_name(self.name, self.private_keys[0],
blockchain_client=blockchain_client, testspace=True)
self.salt = resp['salt']
self.assertTrue('success' in resp)
resp = register_name(self.name, self.salt, self.private_keys[1],
blockchain_client=blockchain_client, testspace=True)
self.assertTrue('success' in resp)
resp = update_name(self.name, self.data, self.private_keys[2],
blockchain_client=blockchain_client, testspace=True)
self.assertTrue('success' in resp)
resp = transfer_name(self.name, self.recipient, self.private_keys[3],
blockchain_client=blockchain_client, testspace=True)
self.assertTrue('success' in resp)"""
def test_main():
test_support.run_unittest(
MerkleRootTest,