mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-10 07:08:05 -05:00
[research/ourobors] fixed bugs in vrf, blockchain
This commit is contained in:
@@ -1 +1,10 @@
|
||||
#dynamic proof of stake blockchain
|
||||
#dynamic proof of stake blockchain
|
||||
from dpos import ouroboros
|
||||
from dpos.ouroboros.vrf import VRF
|
||||
from dpos.ouroboros.environment import Z
|
||||
from dpos.ouroboros.stakeholder import Stakeholder
|
||||
from dpos.ouroboros.clock import SynchedNTPClock
|
||||
from dpos.ouroboros.block import Block, EmptyBlock, GensisBlock
|
||||
from dpos.ouroboros.blockchain import Blockchain
|
||||
from dpos.ouroboros.epoch import Epoch
|
||||
from dpos.ouroboros.utils import *
|
||||
@@ -14,27 +14,28 @@ proof, and base to the genesis block.
|
||||
#TODO implement trustedbeacon as a node
|
||||
'''
|
||||
class TrustedBeacon(SynchedNTPClock, threading.Thread):
|
||||
def __init__(self, node, vrf_sk, epoch_length, genesis_time):
|
||||
def __init__(self, node, vrf, epoch_length, genesis_time):
|
||||
self.epoch_length=epoch_length # how many slots in a a block
|
||||
SynchedNTPClock.__init__(self)
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon=True
|
||||
self.node = node #stakeholder
|
||||
self.vrf = VRF(self.node.vrf_pk, vrf_sk, self.node.vrf_base)
|
||||
self.vrf = vrf
|
||||
self.current_slot = self.slot
|
||||
self.log = Logger(self, genesis_time)
|
||||
self.log.info(f"[TrustedBeacon] constructed for node {str(node)}")
|
||||
self.log.info(f"constructed for node {str(node)}")
|
||||
|
||||
def __repr__(self):
|
||||
return f"trustedbeacon"
|
||||
|
||||
def run(self):
|
||||
self.log.info("[TrustedBeacon] thread [start]")
|
||||
self.log.highlight("thread [start]")
|
||||
self.__background()
|
||||
self.log.info("[TrustedBeacon] thread [end]")
|
||||
self.log.info("thread [end]")
|
||||
|
||||
def __background(self):
|
||||
current_epoch = self.slot
|
||||
self.log.info('background waiting for the onset of next synched epoch...')
|
||||
while True:
|
||||
if self.slot != current_epoch:
|
||||
current_epoch = self.slot
|
||||
@@ -42,19 +43,20 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread):
|
||||
|
||||
def __callback(self):
|
||||
self.current_slot = self.slot
|
||||
sigmas = []
|
||||
proofs = []
|
||||
for i in range(self.epoch_length):
|
||||
self.log.info(f"[TrustedBeacon] callback: new slot of idx: {self.current_slot}, epoch slot {i}")
|
||||
if self.current_slot%self.epoch_length!=0:
|
||||
self.log.info(f"callback: new slot of idx: {self.current_slot}")
|
||||
y, pi = self.vrf.sign(self.current_slot)
|
||||
self.log.info(f"[TrustedBeacon] callback: signature calculated for {str(self.node)}")
|
||||
sigmas.append(y)
|
||||
proofs.append(pi)
|
||||
if self.current_slot%self.epoch_length==0:
|
||||
self.log.info(["[TrustedBeacon] new slot"])
|
||||
self.node.new_slot(self.current_slot, sigmas[0], proofs[0])
|
||||
self.log.info(f"callback: signature calculated for {str(self.node)}")
|
||||
self.node.new_slot(self.current_slot, y, pi)
|
||||
else:
|
||||
self.log.info([f"[TrustedBeacon] new epoch with simgas of size:{len(sigmas)}, proofs: {len(proofs)}"])
|
||||
sigmas = []
|
||||
proofs = []
|
||||
for i in range(self.epoch_length):
|
||||
self.log.info(f"callback: new slot of idx: {self.current_slot}, epoch slot {i}")
|
||||
y, pi = self.vrf.sign(self.current_slot)
|
||||
self.log.info(f"callback: signature calculated for {str(self.node)}")
|
||||
sigmas.append(y)
|
||||
proofs.append(pi)
|
||||
self.node.new_epoch(self.current_slot, sigmas, proofs)
|
||||
|
||||
def verify(self, y, pi, pk_raw, g):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
from ouroboros.utils import encode_genesis_data, decode_gensis_data, state_hash
|
||||
from ouroboros.consts import *
|
||||
|
||||
'''
|
||||
single block B_i for slot i in the system live time L,
|
||||
@@ -30,6 +31,16 @@ class Block(object):
|
||||
decode_gensis_data(self.data)
|
||||
return "Block at {slot:"+self.sl+",data:"+self.tx+",state:"+self.state+"}"
|
||||
|
||||
def __hash__(self):
|
||||
if type(self.tx)==str:
|
||||
return hash((self.state, self.tx, self.sl))
|
||||
elif type(self.tx)==dict:
|
||||
#TODO include distribution
|
||||
return hash((self.state, self.tx[SEED], self.tx[TX]))
|
||||
else:
|
||||
#TODO (fix) shouldn't reach here
|
||||
return 0
|
||||
|
||||
def __eq__(self, block):
|
||||
return self.state==block.state and \
|
||||
self.tx == block.tx and \
|
||||
@@ -62,10 +73,15 @@ class GensisBlock(Block):
|
||||
'''
|
||||
def __init__(self, previous_block, data, slot_uid):
|
||||
# stakeholders is list of tuple (pk_i, s_i) for the ith stakeholder
|
||||
self.stakeholders = data['stakeholders']
|
||||
self.seed = data['seed']
|
||||
data = encode_genesis_data(self.stakeholders, self.seed)
|
||||
Block.__init__(self, previous_block, data, slot_uid, True)
|
||||
self.stakeholders = data[STAKEHOLDERS]
|
||||
self.distribution = data[STAKEHOLDERS_DISTRIBUTIONS]
|
||||
self.seed = data.get(SEED, '') #needed for pvss
|
||||
shd_buff = ''
|
||||
for shd in self.distribution:
|
||||
shd_buff +=str(shd)
|
||||
#data = encode_genesis_data(shd_buff)
|
||||
data_dict = {'seed':self.seed, 'distribution':shd_buff}
|
||||
Block.__init__(self, previous_block, str(data_dict), slot_uid, True)
|
||||
'''
|
||||
@return: the number of participating stakeholders in the blockchain
|
||||
'''
|
||||
|
||||
@@ -17,7 +17,7 @@ class Blockchain(object):
|
||||
def __repr__(self):
|
||||
buff=''
|
||||
for i in range(len(self.blocks)):
|
||||
buff+=self.blocks[i]
|
||||
buff+=str(self.blocks[i])
|
||||
return buff
|
||||
|
||||
def __getitem__(self, i):
|
||||
@@ -30,6 +30,8 @@ class Blockchain(object):
|
||||
self.blocks.append(block)
|
||||
|
||||
def add_epoch(self, epoch):
|
||||
assert epoch!=None, 'epoch cant be None'
|
||||
assert len(epoch)>0 , 'epoch cant be zero-sized'
|
||||
for idx, block in enumerate(epoch):
|
||||
if not block.empty:
|
||||
self.__add_block(block)
|
||||
|
||||
@@ -8,7 +8,7 @@ import math
|
||||
|
||||
class SynchedNTPClock(object):
|
||||
|
||||
def __init__(self, slot_length=180, ntp_server='europe.pool.ntp.org'):
|
||||
def __init__(self, slot_length=1, ntp_server='europe.pool.ntp.org'):
|
||||
#TODO how long should be the slot length
|
||||
self.slot_length=slot_length
|
||||
self.ntp_server = ntp_server
|
||||
|
||||
4
script/research/dpos/ouroboros/consts.py
Normal file
4
script/research/dpos/ouroboros/consts.py
Normal file
@@ -0,0 +1,4 @@
|
||||
STAKEHOLDERS_DISTRIBUTIONS='distributions'
|
||||
STAKEHOLDERS='stakeholders'
|
||||
SEED='seed'
|
||||
TX='tx'
|
||||
@@ -2,6 +2,7 @@ import numpy as np
|
||||
import math
|
||||
import random
|
||||
from ouroboros.logger import Logger
|
||||
from ouroboros.consts import *
|
||||
import time
|
||||
'''
|
||||
\class Z is the environment
|
||||
@@ -27,8 +28,11 @@ class Z(object):
|
||||
return genesis data of the current epoch
|
||||
'''
|
||||
def get_genesis_data(self):
|
||||
#TODO implement dynaming staking
|
||||
return ''
|
||||
#TODO implement dynaming staking
|
||||
genesis_data = {STAKEHOLDERS: self.stakeholders,
|
||||
STAKEHOLDERS_DISTRIBUTIONS:[],
|
||||
SEED: ''}
|
||||
return genesis_data
|
||||
|
||||
@property
|
||||
def current_leader_id(self):
|
||||
@@ -74,8 +78,7 @@ class Z(object):
|
||||
return len(self.stakeholders[self.adversary_mask])
|
||||
|
||||
def select_epoch_leaders(self, sigmas, proofs):
|
||||
if len(sigmas)==self.epoch_length or len(proofs)==self.epoch_length:
|
||||
self.log.error(f"size mismatch between sigmas: {len(sigmas)}, proofs: {len(proofs)}, and epoch_length: {self.epoch_length}")
|
||||
assert len(sigmas)==self.epoch_length and len(proofs)==self.epoch_length, self.log.error(f"size mismatch between sigmas: {len(sigmas)}, proofs: {len(proofs)}, and epoch_length: {self.epoch_length}")
|
||||
for i in range(self.epoch_length):
|
||||
self.log.info(f"current sigma of index {i} of total {len(sigmas)}, epoch_length: {self.epoch_length}")
|
||||
sigma = sigmas[i]
|
||||
@@ -120,11 +123,9 @@ class Z(object):
|
||||
def start(self):
|
||||
for sh in self.stakeholders:
|
||||
sh(self)
|
||||
self.log.info("Z.start [started]")
|
||||
for sh in self.stakeholders:
|
||||
sh.start()
|
||||
self.log.info("Z.start [ended]")
|
||||
|
||||
def print_blockchain(self):
|
||||
bc = self.stakeholders[0].blockchain
|
||||
self.log.info(f"blockchain of {len(bc)} blocks: "+str(bc))
|
||||
self.log.info(f"<blockchain> {len(bc)} blocks: "+str(bc))
|
||||
@@ -1,17 +1,20 @@
|
||||
from ouroboros.utils import state_hash
|
||||
from ouroboros.logger import Logger
|
||||
|
||||
class Epoch(object):
|
||||
class Epoch(list):
|
||||
'''
|
||||
epoch spans R slots,
|
||||
maximum number of block in Epoch is R
|
||||
epoch must start with gensis block B0
|
||||
'''
|
||||
def __init__(self, gensis_block, R, epoch_idx):
|
||||
def __init__(self, gensis_block, R, epoch_idx, genesis_time):
|
||||
self.gensis_block=gensis_block
|
||||
self.blocks = []
|
||||
self.R = R #maximum epoch legnth, and it's a fixed property of the system
|
||||
self.e = epoch_idx
|
||||
self.index=0
|
||||
self.n=0
|
||||
self.log = Logger(genesis_time)
|
||||
|
||||
@property
|
||||
def slot(self):
|
||||
return self.gensis_block.sl
|
||||
@@ -30,24 +33,30 @@ class Epoch(object):
|
||||
return None
|
||||
return self.blocks[0]
|
||||
|
||||
def __len__(self):
|
||||
return self.length
|
||||
|
||||
def add_block(self, block):
|
||||
if len(self.blocks)>0 and not block.state==state_hash(self.block[-1]):
|
||||
if len(self.blocks)>0 and not block.state==state_hash(self.blocks[-1]):
|
||||
#TODO we dealing with corrupt stakeholder,
|
||||
# action to be taken
|
||||
# the caller of the add_block should execute (corrupt,U)
|
||||
pass
|
||||
|
||||
if self.length==self.R:
|
||||
raise f"can't exceed Epoch's length: {self.length}"
|
||||
self.log.error(f"epoch length: {self.length} can't exceed Epoch's length: {self.R}")
|
||||
self.blocks.append(block)
|
||||
|
||||
def __iter__(self):
|
||||
self.n=0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
blk=None
|
||||
for i in range(self.length):
|
||||
try:
|
||||
res=self.blocks[self.index]
|
||||
blk=self.blocks[self.n]
|
||||
except IndexError:
|
||||
raise StopIteration
|
||||
self.index+=1
|
||||
return res
|
||||
self.n+=1
|
||||
return blk
|
||||
@@ -14,11 +14,14 @@ class Logger(object):
|
||||
return round(d,1)
|
||||
|
||||
def info(self, payload):
|
||||
print("\033[32m", f"[{self.diff}] - [{self.obj}]:\n\t{payload}\n", "\033[0m")
|
||||
print("\033[32m", f"[{self.diff}] - [{type(self.obj).__name__}] {self.obj}:\n\t{payload}\n", "\033[0m")
|
||||
|
||||
def highlight(self, payload):
|
||||
print("\033[35m", f"[{self.diff}] - [{type(self.obj).__name__}] {self.obj}:\n\t{payload}\n", "\033[0m")
|
||||
|
||||
def warn(self, payload):
|
||||
print("\033[33m", f"[{self.diff}] - [{self.obj}]:\n\t{payload}\n", "\033[0m")
|
||||
print("\033[33m", f"[{self.diff}] - [{type(self.obj).__name__}] {self.obj}:\n\t{payload}\n", "\033[0m")
|
||||
|
||||
def error(self, payload):
|
||||
print("\033[31m", f"[{self.diff}] - [{self.obj}]:\n\t{payload}\n", "\033[0m")
|
||||
print("\033[31m", f"[{self.diff}] - [{type(self.obj).__name__}] {self.obj}:\n\t{payload}\n", "\033[0m")
|
||||
exit()
|
||||
|
||||
@@ -3,24 +3,25 @@ from ouroboros.block import Block, GensisBlock, EmptyBlock
|
||||
from ouroboros.blockchain import Blockchain
|
||||
from ouroboros.epoch import Epoch
|
||||
from ouroboros.beacon import TrustedBeacon
|
||||
from ouroboros.vrf import generate_vrf_keys, VRF
|
||||
from ouroboros.vrf import verify, VRF
|
||||
from ouroboros.utils import *
|
||||
from ouroboros.logger import Logger
|
||||
from ouroboros.consts import *
|
||||
import time
|
||||
'''
|
||||
\class Stakeholder
|
||||
'''
|
||||
class Stakeholder(object):
|
||||
def __init__(self, epoch_length=100, passwd='password'):
|
||||
def __init__(self, epoch_length=2, passwd='password'):
|
||||
#TODO (fix) remove redundant variables reley on environment
|
||||
self.passwd=passwd
|
||||
self.stake=0
|
||||
self.epoch_length=epoch_length
|
||||
pk, sk, g = generate_vrf_keys(self.passwd)
|
||||
self.vrf = VRF(self.passwd)
|
||||
#verification keys
|
||||
self.__vrf_pk = pk
|
||||
self.__vrf_sk = sk
|
||||
self.__vrf_base = g
|
||||
self.__vrf_pk = self.vrf.pk
|
||||
self.__vrf_sk = self.vrf.sk
|
||||
self.__vrf_base = self.vrf.g
|
||||
#signature keys
|
||||
sig_sk, sig_pk = generate_sig_keys(self.passwd)
|
||||
self.sig_sk = sig_sk
|
||||
@@ -56,19 +57,27 @@ class Stakeholder(object):
|
||||
self.env=env
|
||||
self.log = Logger(self, self.env.genesis_time)
|
||||
self.blockchain = Blockchain(self.epoch_length, self.env.genesis_time)
|
||||
self.beacon = TrustedBeacon(self, self.__vrf_sk, self.epoch_length, self.env.genesis_time)
|
||||
self.beacon = TrustedBeacon(self, self.vrf, self.epoch_length, self.env.genesis_time)
|
||||
self.current_slot_uid = self.beacon.slot
|
||||
|
||||
|
||||
def start(self):
|
||||
self.log.info("Stakeholder.start [started]")
|
||||
self.log.info("start [started]")
|
||||
self.beacon.start()
|
||||
self.log.info("Stakeholder.start [ended]")
|
||||
self.log.info("start [ended]")
|
||||
|
||||
@property
|
||||
def epoch_index(self):
|
||||
return round(self.current_slot_uid/self.epoch_length)
|
||||
|
||||
def __gen_genesis_epoch(self):
|
||||
'''
|
||||
'''
|
||||
self.tx = self.env.get_genesis_data()
|
||||
self.tx[TX]=self.uncommited_tx
|
||||
self.uncommited_tx=''
|
||||
self.current_block=GensisBlock(self.current_block, self.tx, self.current_slot_uid)
|
||||
self.current_epoch=Epoch(self.current_block, self.epoch_length, self.epoch_index, self.env.genesis_time)
|
||||
'''
|
||||
it's a callback function, and called by the diffuser
|
||||
'''
|
||||
@@ -78,17 +87,15 @@ class Stakeholder(object):
|
||||
for this implementation we assume synchrony,
|
||||
and at this point, and no delay is considered (for simplicity)
|
||||
'''
|
||||
self.log.info("[stakeholder.new_epoch] start")
|
||||
self.log.highlight("<new_epoch> start")
|
||||
self.env.new_epoch(slot, sigmas, proofs)
|
||||
self.current_slot_uid = slot
|
||||
# add epoch to the ledger
|
||||
if self.current_slot_uid > 1:
|
||||
self.blockchain.add_epoch(self.current_epoch)
|
||||
#kickoff gensis block
|
||||
self.tx = self.env.get_genesis_data()
|
||||
self.current_block=GensisBlock(self.current_block, self.tx, self.current_slot_uid)
|
||||
self.current_epoch=Epoch(self.current_block, self.epoch_length, self.epoch_index)
|
||||
# add old epoch to the ledger
|
||||
if self.current_slot_uid > 1 and self.current_epoch!=None and len(self.current_epoch)>0:
|
||||
self.blockchain.add_epoch(self.current_epoch)
|
||||
#if leader, you need to broadcast the block
|
||||
self.__gen_genesis_epoch()
|
||||
if self.am_current_leader:
|
||||
self.broadcast_block()
|
||||
|
||||
@@ -101,26 +108,27 @@ class Stakeholder(object):
|
||||
for this implementation we assume synchrony,
|
||||
and at this point, and no delay is considered (for simplicity)
|
||||
'''
|
||||
self.log.info("[stakeholder.new_slot] start")
|
||||
self.log.highlight("<new_slot> start")
|
||||
self.env.new_slot(slot, sigma, proof)
|
||||
vrf_pk = self.env.current_leader_vrf_pk
|
||||
vrf_g = self.env.current_leader_vrf_g
|
||||
assert(vrf_pk!=None)
|
||||
assert(vrf_g!=None)
|
||||
if not VRF.verify(slot, sigma, proof, vrf_pk,vrf_g) :
|
||||
if not verify(slot, sigma, proof, vrf_pk,vrf_g) :
|
||||
#TODO the leader is corrupted, action to be taken against the corrupt stakeholder
|
||||
#in this case this slot is empty
|
||||
self.current_block=EmptyBlock()
|
||||
if self.current_epoch!=None:
|
||||
self.current_epoch.add_block(self.current_block)
|
||||
else:
|
||||
#TODO (fix) this shouldn't happen!
|
||||
self.log.info(f"[Stakeholder] new_slot, current_epoch is None!")
|
||||
return
|
||||
self.log.warn(f"<new_slot> current_epoch is None!")
|
||||
return
|
||||
if self.current_epoch==None:
|
||||
self.log.warn(f"<new_slot> current_epoch is None!")
|
||||
self.__gen_genesis_epoch()
|
||||
self.current_slot_uid = slot
|
||||
self.current_block=Block(self.current_block, self.tx, self.current_slot_uid)
|
||||
self.current_epoch.add_block(self.current_block)
|
||||
#TODO if leader you need to broadcast the block
|
||||
if self.am_current_leader:
|
||||
self.broadcast_block()
|
||||
|
||||
@@ -134,6 +142,7 @@ class Stakeholder(object):
|
||||
self.am_corrupt=False
|
||||
|
||||
def broadcast_block(self):
|
||||
self.log.highlight("broadcasting block")
|
||||
assert(self.am_current_leader)
|
||||
signed_block = sign_message(self.passwd, self.sig_sk, self.current_block)
|
||||
self.env.broadcast_block(signed_block)
|
||||
@@ -141,6 +150,7 @@ class Stakeholder(object):
|
||||
|
||||
|
||||
def receive_block(self, received_block):
|
||||
self.log.highlight("receiving block")
|
||||
if verify_signature(self.env.current_leader_sig_pk, self.current_block, received_block):
|
||||
pass
|
||||
else:
|
||||
|
||||
@@ -5,30 +5,23 @@ from ouroboros.utils import inverse_of
|
||||
from ouroboros.utils import vrf_hash
|
||||
eta.init(369)
|
||||
|
||||
'''
|
||||
gernate vrf keys for stakeholder
|
||||
@param sk_seed: this is suppoed to be the password of the stakeholder
|
||||
'''
|
||||
def generate_vrf_keys(sk_seed):
|
||||
'''
|
||||
generate pk/sk
|
||||
return: list of pk (public key), sk(secret key), base(field base)
|
||||
'''
|
||||
sk = vrf_hash(sk_seed)
|
||||
base = ecc.gen()
|
||||
pk = ecc.scalar_mult(sk, base)
|
||||
return (pk, sk, base)
|
||||
|
||||
class VRF(object):
|
||||
'''
|
||||
verifiable random function implementation
|
||||
'''
|
||||
def __init__(self, pk, sk, base):
|
||||
self.pk = pk
|
||||
self.sk = sk
|
||||
self.g=base
|
||||
def __init__(self, seed):
|
||||
self.log = Logger(self)
|
||||
self.order = ecc.order()
|
||||
#TODO use ecc to gen sk
|
||||
sk = vrf_hash(seed) % self.order
|
||||
g = ecc.gen()
|
||||
pk = ecc.scalar_mult(sk, g)
|
||||
#
|
||||
self.pk = pk
|
||||
self.sk = sk
|
||||
self.g=g
|
||||
|
||||
|
||||
'''
|
||||
short signature without random oracle
|
||||
@@ -50,12 +43,32 @@ class VRF(object):
|
||||
@param x: signed messaged
|
||||
@param y: signature
|
||||
@param pi: [inf, x, y] proof components
|
||||
@param pk: [inf, x, y] public key components of the prover
|
||||
@param g: group base
|
||||
'''
|
||||
def verify(x, y, pi, pk_raw, g):
|
||||
def verify(self, x, y, pi):
|
||||
gx = ecc.scalar_mult(x, self.g)
|
||||
rhs = eta.pairing(*ecc.scalar_mult(1,self.g)[1:], *pi[1:])
|
||||
if not y == rhs:
|
||||
print(f"y: {y}, rhs: {rhs}")
|
||||
return False
|
||||
gxs = ecc.add(gx, self.pk)
|
||||
lhs = eta.pairing(*gxs[1:], *pi[1:])
|
||||
rhs = eta.pairing(*ecc.scalar_mult(1, self.g)[1:], *ecc.scalar_mult(1, self.g)[1:])
|
||||
if not lhs==rhs:
|
||||
print(f"proposed {x}, {y}, {pi}, {self.pk}, {self.g}")
|
||||
print(f"lhs: {lhs},\nrhs: {rhs}")
|
||||
return False
|
||||
return True
|
||||
|
||||
'''
|
||||
verify signature
|
||||
@param x: signed messaged
|
||||
@param y: signature
|
||||
@param pi: [inf, x, y] proof components
|
||||
@param pk: [inf, x, y] public key components of the prover
|
||||
@param g: group base
|
||||
'''
|
||||
def verify(x, y, pi, pk_raw, g):
|
||||
gx = ecc.scalar_mult(x, g)
|
||||
#pk = ecc.scalar_mult(1, pk_raw)
|
||||
rhs = eta.pairing(*ecc.scalar_mult(1,g)[1:], *pi[1:])
|
||||
if not y == rhs:
|
||||
print(f"y: {y}, rhs: {rhs}")
|
||||
|
||||
@@ -2,13 +2,13 @@ from ouroboros import Stakeholder
|
||||
from ouroboros import Z
|
||||
import time
|
||||
|
||||
EPOCH_LENGTH = 3
|
||||
EPOCH_LENGTH = 2
|
||||
stakeholders = []
|
||||
for i in range(3):
|
||||
|
||||
for i in range(2):
|
||||
stakeholders.append(Stakeholder(EPOCH_LENGTH))
|
||||
|
||||
environment = Z(stakeholders, EPOCH_LENGTH, genesis_time=time.time())
|
||||
|
||||
environment.start()
|
||||
|
||||
for sh in environment.stakeholders:
|
||||
|
||||
10
script/research/dpos/vrf_test.py
Normal file
10
script/research/dpos/vrf_test.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from ouroboros.vrf import VRF, verify
|
||||
|
||||
seed='seed'
|
||||
m=234234234
|
||||
|
||||
vrf = VRF(seed)
|
||||
y, pi = vrf.sign(m)
|
||||
|
||||
assert vrf.verify(m, y, pi), 'verification failed'
|
||||
assert verify(m, y, pi, vrf.pk, vrf.g), 'verification failed'
|
||||
Reference in New Issue
Block a user