Browse Source

[research/ourobors] fixed bugs in vrf, blockchain

mohab 4 years ago
parent
commit
4eee40e873

+ 10 - 1
script/research/dpos/__init__.py

@@ -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 *

+ 0 - 0
script/research/dpos/ouroboros-test/__init__.py


+ 18 - 16
script/research/dpos/ouroboros/beacon.py

@@ -14,27 +14,28 @@ proof, and base to the genesis block.
 #TODO implement trustedbeacon as a node
 #TODO implement trustedbeacon as a node
 '''
 '''
 class TrustedBeacon(SynchedNTPClock, threading.Thread):
 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
         self.epoch_length=epoch_length # how many slots in a a block
         SynchedNTPClock.__init__(self)
         SynchedNTPClock.__init__(self)
         threading.Thread.__init__(self)
         threading.Thread.__init__(self)
         self.daemon=True
         self.daemon=True
         self.node = node #stakeholder
         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.current_slot = self.slot
         self.log = Logger(self, genesis_time)
         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):
     def __repr__(self):
         return f"trustedbeacon"
         return f"trustedbeacon"
 
 
     def run(self):
     def run(self):
-        self.log.info("[TrustedBeacon] thread [start]")
+        self.log.highlight("thread [start]")
         self.__background()
         self.__background()
-        self.log.info("[TrustedBeacon] thread [end]")
+        self.log.info("thread [end]")
 
 
     def __background(self):
     def __background(self):
         current_epoch = self.slot
         current_epoch = self.slot
+        self.log.info('background waiting for the onset of next synched epoch...')
         while True:
         while True:
             if self.slot != current_epoch:
             if self.slot != current_epoch:
                 current_epoch = self.slot
                 current_epoch = self.slot
@@ -42,19 +43,20 @@ class TrustedBeacon(SynchedNTPClock, threading.Thread):
 
 
     def __callback(self):
     def __callback(self):
         self.current_slot = self.slot
         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)
             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:
         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)
             self.node.new_epoch(self.current_slot, sigmas, proofs)
 
 
     def verify(self, y, pi, pk_raw, g):
     def verify(self, y, pi, pk_raw, g):

+ 20 - 4
script/research/dpos/ouroboros/block.py

@@ -1,5 +1,6 @@
 import json
 import json
 from ouroboros.utils import encode_genesis_data, decode_gensis_data, state_hash
 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,
 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)
                 decode_gensis_data(self.data)
         return "Block at {slot:"+self.sl+",data:"+self.tx+",state:"+self.state+"}"
         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):
     def __eq__(self, block):
         return self.state==block.state and \
         return self.state==block.state and \
             self.tx == block.tx and \
             self.tx == block.tx and \
@@ -62,10 +73,15 @@ class GensisBlock(Block):
     '''
     '''
     def __init__(self, previous_block, data, slot_uid):
     def __init__(self, previous_block, data, slot_uid):
         # stakeholders is list of tuple (pk_i, s_i) for the ith stakeholder
         # 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
     @return: the number of participating stakeholders in the blockchain
     '''
     '''

+ 3 - 1
script/research/dpos/ouroboros/blockchain.py

@@ -17,7 +17,7 @@ class Blockchain(object):
     def __repr__(self):
     def __repr__(self):
         buff=''
         buff=''
         for i in range(len(self.blocks)):
         for i in range(len(self.blocks)):
-            buff+=self.blocks[i]
+            buff+=str(self.blocks[i])
         return buff
         return buff
     
     
     def __getitem__(self, i):
     def __getitem__(self, i):
@@ -30,6 +30,8 @@ class Blockchain(object):
         self.blocks.append(block)
         self.blocks.append(block)
 
 
     def add_epoch(self, epoch):
     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):
         for idx, block in enumerate(epoch):
             if not block.empty:
             if not block.empty:
                 self.__add_block(block)
                 self.__add_block(block)

+ 1 - 1
script/research/dpos/ouroboros/clock.py

@@ -8,7 +8,7 @@ import math
 
 
 class SynchedNTPClock(object):
 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
         #TODO how long should be the slot length
         self.slot_length=slot_length
         self.slot_length=slot_length
         self.ntp_server = ntp_server
         self.ntp_server = ntp_server

+ 4 - 0
script/research/dpos/ouroboros/consts.py

@@ -0,0 +1,4 @@
+STAKEHOLDERS_DISTRIBUTIONS='distributions'
+STAKEHOLDERS='stakeholders'
+SEED='seed'
+TX='tx'

+ 8 - 7
script/research/dpos/ouroboros/environment.py

@@ -2,6 +2,7 @@ import numpy as np
 import math
 import math
 import random
 import random
 from ouroboros.logger import Logger
 from ouroboros.logger import Logger
+from ouroboros.consts import *
 import time
 import time
 '''
 '''
 \class Z is the environment
 \class Z is the environment
@@ -27,8 +28,11 @@ class Z(object):
         return genesis data of the current epoch
         return genesis data of the current epoch
     '''
     '''
     def get_genesis_data(self):
     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
     @property
     def current_leader_id(self):
     def current_leader_id(self):
@@ -74,8 +78,7 @@ class Z(object):
         return len(self.stakeholders[self.adversary_mask])
         return len(self.stakeholders[self.adversary_mask])
 
 
     def select_epoch_leaders(self, sigmas, proofs):
     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):
         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}")
             self.log.info(f"current sigma of index {i} of total {len(sigmas)}, epoch_length: {self.epoch_length}")
             sigma = sigmas[i]
             sigma = sigmas[i]
@@ -120,11 +123,9 @@ class Z(object):
     def start(self):
     def start(self):
         for sh in self.stakeholders:
         for sh in self.stakeholders:
             sh(self)
             sh(self)
-        self.log.info("Z.start [started]")
         for sh in self.stakeholders:
         for sh in self.stakeholders:
             sh.start()
             sh.start()
-        self.log.info("Z.start [ended]")
 
 
     def print_blockchain(self):
     def print_blockchain(self):
         bc = self.stakeholders[0].blockchain
         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))

+ 17 - 8
script/research/dpos/ouroboros/epoch.py

@@ -1,17 +1,20 @@
 from ouroboros.utils import state_hash
 from ouroboros.utils import state_hash
+from ouroboros.logger import Logger
 
 
-class Epoch(object):
+class Epoch(list):
     '''
     '''
     epoch spans R slots, 
     epoch spans R slots, 
     maximum number of block in Epoch is R
     maximum number of block in Epoch is R
     epoch must start with gensis block B0
     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.gensis_block=gensis_block
         self.blocks = []
         self.blocks = []
         self.R = R #maximum epoch legnth, and it's a fixed property of the system
         self.R = R #maximum epoch legnth, and it's a fixed property of the system
         self.e = epoch_idx
         self.e = epoch_idx
-        self.index=0
+        self.n=0
+        self.log = Logger(genesis_time)
+
     @property
     @property
     def slot(self):
     def slot(self):
         return self.gensis_block.sl
         return self.gensis_block.sl
@@ -30,24 +33,30 @@ class Epoch(object):
             return None
             return None
         return self.blocks[0]
         return self.blocks[0]
 
 
+    def __len__(self):
+        return self.length
+
     def add_block(self, block):
     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,
             #TODO we dealing with corrupt stakeholder,
             # action to be taken
             # action to be taken
             # the caller of the add_block should execute (corrupt,U)
             # the caller of the add_block should execute (corrupt,U)
             pass
             pass
+
         if self.length==self.R:
         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)
         self.blocks.append(block)
     
     
     def __iter__(self):
     def __iter__(self):
+        self.n=0
         return self
         return self
     
     
     def __next__(self):
     def __next__(self):
+        blk=None
         for i in range(self.length):
         for i in range(self.length):
             try:
             try:
-                res=self.blocks[self.index]
+                blk=self.blocks[self.n]
             except IndexError:
             except IndexError:
                 raise StopIteration
                 raise StopIteration
-            self.index+=1
-            return res
+            self.n+=1
+            return blk

+ 6 - 3
script/research/dpos/ouroboros/logger.py

@@ -14,11 +14,14 @@ class Logger(object):
         return round(d,1)
         return round(d,1)
 
 
     def info(self, payload):
     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):
     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):
     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()
         exit()

+ 32 - 22
script/research/dpos/ouroboros/stakeholder.py

@@ -3,24 +3,25 @@ from ouroboros.block import Block, GensisBlock, EmptyBlock
 from ouroboros.blockchain import Blockchain
 from ouroboros.blockchain import Blockchain
 from ouroboros.epoch import Epoch
 from ouroboros.epoch import Epoch
 from ouroboros.beacon import TrustedBeacon
 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.utils import *
 from ouroboros.logger import Logger
 from ouroboros.logger import Logger
+from ouroboros.consts import *
 import time
 import time
 '''
 '''
 \class Stakeholder
 \class Stakeholder
 '''
 '''
 class Stakeholder(object):
 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
         #TODO (fix) remove redundant variables reley on environment
         self.passwd=passwd
         self.passwd=passwd
         self.stake=0
         self.stake=0
         self.epoch_length=epoch_length
         self.epoch_length=epoch_length
-        pk, sk, g = generate_vrf_keys(self.passwd)
+        self.vrf = VRF(self.passwd)
         #verification keys
         #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
         #signature keys
         sig_sk, sig_pk = generate_sig_keys(self.passwd)
         sig_sk, sig_pk = generate_sig_keys(self.passwd)
         self.sig_sk = sig_sk
         self.sig_sk = sig_sk
@@ -56,19 +57,27 @@ class Stakeholder(object):
         self.env=env
         self.env=env
         self.log = Logger(self, self.env.genesis_time)
         self.log = Logger(self, self.env.genesis_time)
         self.blockchain = Blockchain(self.epoch_length, 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
         self.current_slot_uid = self.beacon.slot
 
 
 
 
     def start(self):
     def start(self):
-        self.log.info("Stakeholder.start [started]")
+        self.log.info("start [started]")
         self.beacon.start()
         self.beacon.start()
-        self.log.info("Stakeholder.start [ended]")
+        self.log.info("start [ended]")
 
 
     @property
     @property
     def epoch_index(self):
     def epoch_index(self):
         return round(self.current_slot_uid/self.epoch_length)
         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
     it's a callback function, and called by the diffuser
     '''
     '''
@@ -78,17 +87,15 @@ class Stakeholder(object):
         for this implementation we assume synchrony,
         for this implementation we assume synchrony,
         and at this point, and no delay is considered (for simplicity)
         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.env.new_epoch(slot, sigmas, proofs)
         self.current_slot_uid = slot
         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
         #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
         #if leader, you need to broadcast the block
+        self.__gen_genesis_epoch() 
         if self.am_current_leader:
         if self.am_current_leader:
             self.broadcast_block()
             self.broadcast_block()
 
 
@@ -101,26 +108,27 @@ class Stakeholder(object):
         for this implementation we assume synchrony,
         for this implementation we assume synchrony,
         and at this point, and no delay is considered (for simplicity)
         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)
         self.env.new_slot(slot, sigma, proof)
         vrf_pk = self.env.current_leader_vrf_pk
         vrf_pk = self.env.current_leader_vrf_pk
         vrf_g = self.env.current_leader_vrf_g
         vrf_g = self.env.current_leader_vrf_g
         assert(vrf_pk!=None)
         assert(vrf_pk!=None)
         assert(vrf_g!=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
             #TODO the leader is corrupted, action to be taken against the corrupt stakeholder
             #in this case this slot is empty
             #in this case this slot is empty
             self.current_block=EmptyBlock() 
             self.current_block=EmptyBlock() 
             if self.current_epoch!=None:
             if self.current_epoch!=None:
                 self.current_epoch.add_block(self.current_block)
                 self.current_epoch.add_block(self.current_block)
             else:
             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_slot_uid = slot
         self.current_block=Block(self.current_block, self.tx, self.current_slot_uid)
         self.current_block=Block(self.current_block, self.tx, self.current_slot_uid)
         self.current_epoch.add_block(self.current_block)
         self.current_epoch.add_block(self.current_block)
-        #TODO if leader you need to broadcast the block
         if self.am_current_leader:
         if self.am_current_leader:
             self.broadcast_block()
             self.broadcast_block()
 
 
@@ -134,6 +142,7 @@ class Stakeholder(object):
         self.am_corrupt=False
         self.am_corrupt=False
 
 
     def broadcast_block(self):
     def broadcast_block(self):
+        self.log.highlight("broadcasting block")
         assert(self.am_current_leader)
         assert(self.am_current_leader)
         signed_block = sign_message(self.passwd, self.sig_sk, self.current_block)
         signed_block = sign_message(self.passwd, self.sig_sk, self.current_block)
         self.env.broadcast_block(signed_block)
         self.env.broadcast_block(signed_block)
@@ -141,6 +150,7 @@ class Stakeholder(object):
 
 
 
 
     def receive_block(self, received_block):
     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):
         if verify_signature(self.env.current_leader_sig_pk, self.current_block, received_block):
             pass
             pass
         else:
         else:

+ 34 - 21
script/research/dpos/ouroboros/vrf.py

@@ -5,30 +5,23 @@ from ouroboros.utils import inverse_of
 from ouroboros.utils import vrf_hash
 from ouroboros.utils import vrf_hash
 eta.init(369)
 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):
 class VRF(object):
     '''
     '''
     verifiable random function implementation
     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.log = Logger(self)
         self.order = ecc.order()
         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
     short signature without random oracle
@@ -50,12 +43,32 @@ class VRF(object):
     @param x: signed messaged
     @param x: signed messaged
     @param y: signature
     @param y: signature
     @param pi: [inf, x, y] proof components
     @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)
         gx = ecc.scalar_mult(x, g)
-        #pk = ecc.scalar_mult(1, pk_raw)
         rhs = eta.pairing(*ecc.scalar_mult(1,g)[1:], *pi[1:])
         rhs = eta.pairing(*ecc.scalar_mult(1,g)[1:], *pi[1:])
         if not y == rhs:
         if not y == rhs:
             print(f"y: {y}, rhs: {rhs}")
             print(f"y: {y}, rhs: {rhs}")

+ 3 - 3
script/research/dpos/simulation.py

@@ -2,13 +2,13 @@ from ouroboros import Stakeholder
 from ouroboros import Z
 from ouroboros import Z
 import time
 import time
 
 
-EPOCH_LENGTH = 3
+EPOCH_LENGTH = 2
 stakeholders = []
 stakeholders = []
-for i in range(3):
+
+for i in range(2):
     stakeholders.append(Stakeholder(EPOCH_LENGTH))
     stakeholders.append(Stakeholder(EPOCH_LENGTH))
 
 
 environment = Z(stakeholders, EPOCH_LENGTH, genesis_time=time.time())
 environment = Z(stakeholders, EPOCH_LENGTH, genesis_time=time.time())
-
 environment.start()
 environment.start()
 
 
 for sh in environment.stakeholders:
 for sh in environment.stakeholders:

+ 0 - 0
script/research/dpos/ouroboros-test/stakeholder_test.py → script/research/dpos/stakeholder_test.py


+ 10 - 0
script/research/dpos/vrf_test.py

@@ -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'