{"action":"created","comment":{"url":"https://api.github.com/repos/dedis/cothority/pulls/comments/59873220","id":59873220,"diff_hunk":"@@ -0,0 +1,615 @@\n+// Package bftcosi store a novel way of scaling BFT for high scale internet\n+// applications especially blockchains\n+package bftcosi\n+\n+import (\n+\t\"math\"\n+\t\"sync\"\n+\n+\t\"github.com/dedis/cothority/lib/cosi\"\n+\t\"github.com/dedis/cothority/lib/dbg\"\n+\t\"github.com/dedis/cothority/lib/network\"\n+\t\"github.com/dedis/cothority/lib/sda\"\n+\t\"github.com/dedis/crypto/abstract\"\n+)\n+\n+// VerificationFunction can be passes to each protocol node. It will be called\n+// during the (start/handle) challenge prepare phase of the protocol\n+type VerificationFunction func([]byte, chan bool)\n+\n+// ProtocolBFTCoSi is the main struct for running the protocol\n+type ProtocolBFTCoSi struct {\n+\t// the node we are represented-in\n+\t*sda.Node\n+\tMsg []byte\n+\t// the suite we use\n+\tsuite abstract.Suite\n+\t// aggregated public key of the peers\n+\taggregatedPublic abstract.Point\n+\t// prepare-round cosi\n+\tprepare *cosi.Cosi\n+\t// commit-round cosi\n+\tcommit *cosi.Cosi\n+\t// channel for announcement\n+\tannounceChan chan announceChan\n+\t// channel for commitment\n+\tcommitChan chan commitChan\n+\t// Two channels for the challenge through the 2 rounds: difference is that\n+\t// during the commit round, we need the previous signature of the \"prepare\"\n+\t// round.\n+\t// channel for challenge during the prepare phase\n+\tchallengePrepareChan chan challengePrepareChan\n+\t// channel for challenge during the commit phase\n+\tchallengeCommitChan chan challengeCommitChan\n+\t// channel for response\n+\tresponseChan chan responseChan\n+\t// channel to notify when we are done\n+\tdone chan bool\n+\t// channel to notify when the prepare round is finished\n+\tprepareFinishedChan chan bool\n+\t// channel used to wait for the verification of the block\n+\tverifyChan chan bool\n+\n+\t// exceptions given during the rounds that is used in the signature\n+\ttempExceptions []cosi.Exception\n+\n+\t// last block computed\n+\tlastBlock string\n+\t// temporary buffer of \"prepare\" commitments\n+\ttempPrepareCommit []*cosi.Commitment\n+\ttpcMut            sync.Mutex\n+\t// temporary buffer of \"commit\" commitments\n+\ttempCommitCommit []*cosi.Commitment\n+\ttccMut           sync.Mutex\n+\t// temporary buffer of \"prepare\" responses\n+\ttempPrepareResponse []*cosi.Response\n+\ttprMut              sync.Mutex\n+\t// temporary buffer of \"commit\" responses\n+\ttempCommitResponse []*cosi.Response\n+\ttcrMut             sync.Mutex\n+\n+\t// refusal to sign for the commit phase or not. This flag is set during the\n+\t// Challenge of the commit phase and will be used during the response of the\n+\t// commit phase to put an exception or to sign.\n+\tsignRefusal bool\n+\n+\t// onDoneCallback is the callback that will be called at the end of the\n+\t// protocol when all nodes have finished. Either at the end of the response\n+\t// phase of the commit round or at the end of a view change.\n+\tonDoneCallback func()\n+\n+\t// onSignatureDone is the callback that will be called when a signature has\n+\t// been generated ( at the end of the response phase of the commit round)\n+\tonSignatureDone func(*BFTSignature)\n+\n+\t// verificationFun will be called\n+\t// during the (start/handle) challenge prepare phase of the protocol\n+\tverificationFun VerificationFunction\n+\n+\t// bool set to true when the final signature is produced\n+\tdoneSigning chan bool\n+\t// lock associated\n+\tdoneLock sync.Mutex\n+\t// threshold for how much exception\n+\tthreshold int\n+\t// done processing is used to stop the processing of the channels\n+\tdoneProcessing chan bool\n+\n+\t// finale signature that this BFTCoSi round has produced\n+\tfinalSignature *BFTSignature\n+}\n+\n+// NewBFTCoSiProtocol returns a new bftcosi struct\n+func NewBFTCoSiProtocol(n *sda.Node, verify VerificationFunction) (*ProtocolBFTCoSi, error) {\n+\t// initialize the bftcosi node/protocol-instance\n+\tbft := &ProtocolBFTCoSi{\n+\t\tNode:             n,\n+\t\tsuite:            n.Suite(),\n+\t\tprepare:          cosi.NewCosi(n.Suite(), n.Private()),\n+\t\tcommit:           cosi.NewCosi(n.Suite(), n.Private()),\n+\t\tverifyChan:       make(chan bool),\n+\t\tdoneProcessing:   make(chan bool, 2),\n+\t\tdoneSigning:      make(chan bool, 1),\n+\t\tverificationFun:  verify,\n+\t\taggregatedPublic: n.EntityList().Aggregate,\n+\t\tthreshold:        int(2.0 * math.Ceil(float64(len(n.Tree().List()))/3.0)),\n+\t}\n+\n+\t// register channels\n+\tif err := n.RegisterChannel(&bft.announceChan); err != nil {\n+\t\treturn bft, err\n+\t}\n+\tif err := n.RegisterChannel(&bft.commitChan); err != nil {\n+\t\treturn bft, err\n+\t}\n+\tif err := n.RegisterChannel(&bft.challengePrepareChan); err != nil {\n+\t\treturn bft, err\n+\t}\n+\tif err := n.RegisterChannel(&bft.challengeCommitChan); err != nil {\n+\t\treturn bft, err\n+\t}\n+\tif err := n.RegisterChannel(&bft.responseChan); err != nil {\n+\t\treturn bft, err\n+\t}\n+\n+\tn.OnDoneCallback(bft.nodeDone)\n+\n+\treturn bft, nil\n+}\n+\n+// Start will start both rounds \"prepare\" and \"commit\" at same time. The\n+// \"commit\" round will wait till the end of the \"prepare\" round during its\n+// challenge phase.\n+func (bft *ProtocolBFTCoSi) Start() error {\n+\tif err := bft.startAnnouncementPrepare(); err != nil {\n+\t\treturn err\n+\t}\n+\treturn bft.startAnnouncementCommit()\n+}\n+\n+// Dispatch listens on all channels and implements the sda.ProtocolInstance\n+// interface.\n+func (bft *ProtocolBFTCoSi) Dispatch() error {\n+\tfor {\n+\t\tvar err error\n+\t\tselect {\n+\t\tcase msg := <-bft.announceChan:\n+\t\t\t// Announcement\n+\t\t\terr = bft.handleAnnouncement(msg.Announce)\n+\t\tcase msg := <-bft.commitChan:\n+\t\t\t// Commitment\n+\t\t\terr = bft.handleCommit(msg.Commitment)\n+\n+\t\tcase msg := <-bft.challengePrepareChan:\n+\t\t\t// Challenge\n+\t\t\terr = bft.handleChallengePrepare(&msg.ChallengePrepare)\n+\n+\t\tcase msg := <-bft.challengeCommitChan:\n+\t\t\terr = bft.handleChallengeCommit(&msg.ChallengeCommit)\n+\n+\t\tcase msg := <-bft.responseChan:\n+\t\t\t// Response\n+\t\t\tswitch msg.Response.TYPE {\n+\t\t\tcase RoundPrepare:\n+\t\t\t\terr = bft.handleResponsePrepare(&msg.Response)\n+\t\t\tcase RoundCommit:\n+\t\t\t\terr = bft.handleResponseCommit(&msg.Response)\n+\t\t\t}\n+\t\tcase <-bft.doneProcessing:\n+\t\t\t// we are done\n+\t\t\tdbg.Lvl2(bft.Name(), \"BFTCoSi Dispatches stop.\")\n+\n+\t\t\treturn nil\n+\t\t}\n+\t\tif err != nil {\n+\t\t\tdbg.Error(\"Error handling messages:\", err)\n+\t\t}\n+\t}\n+}\n+\n+// startAnnouncementPrepare create its announcement for the prepare round and\n+// sends it down the tree.\n+func (bft *ProtocolBFTCoSi) startAnnouncementPrepare() error {\n+\tann := bft.prepare.CreateAnnouncement()\n+\ta := &Announce{\n+\t\tTYPE:         RoundPrepare,\n+\t\tAnnouncement: ann,\n+\t}\n+\tdbg.Lvl3(\"BFTCoSi Start Announcement (PREPARE)\")\n+\treturn bft.sendAnnouncement(a)\n+}\n+\n+// startAnnouncementCommit create the announcement for the commit phase and\n+// sends it down the tree.\n+func (bft *ProtocolBFTCoSi) startAnnouncementCommit() error {\n+\tann := bft.commit.CreateAnnouncement()\n+\ta := &Announce{\n+\t\tTYPE:         RoundCommit,\n+\t\tAnnouncement: ann,\n+\t}\n+\tdbg.Lvl3(bft.Name(), \"BFTCoSi Start Announcement (COMMIT)\")\n+\treturn bft.sendAnnouncement(a)\n+}\n+\n+func (bft *ProtocolBFTCoSi) sendAnnouncement(a *Announce) error {\n+\tvar err error\n+\tfor _, tn := range bft.Children() {\n+\t\terr = bft.SendTo(tn, a)\n+\t}\n+\treturn err\n+}\n+\n+// handleAnnouncement pass the announcement to the right CoSi struct.\n+func (bft *ProtocolBFTCoSi) handleAnnouncement(ann Announce) error {\n+\tannouncement := &Announce{\n+\t\tAnnouncement: bft.prepare.Announce(ann.Announcement),\n+\t}\n+\n+\tswitch ann.TYPE {\n+\tcase RoundPrepare:\n+\t\tdbg.Lvl3(bft.Name(), \"BFTCoSi Handle Announcement PREPARE\")\n+\t\tif bft.IsLeaf() {\n+\t\t\treturn bft.startCommitmentPrepare()\n+\t\t}\n+\t\tannouncement.TYPE = RoundPrepare\n+\tcase RoundCommit:\n+\t\tdbg.Lvl3(bft.Name(), \"BFTCoSi Handle Announcement COMMIT\")\n+\t\tif bft.IsLeaf() {\n+\t\t\treturn bft.startCommitmentCommit()\n+\t\t}\n+\t\tannouncement.TYPE = RoundCommit\n+\t}\n+\n+\tvar err error\n+\tfor _, tn := range bft.Children() {\n+\t\terr = bft.SendTo(tn, announcement)\n+\t}\n+\treturn err\n+}\n+\n+// startPrepareCommitment send the first commitment up the tree for the prepare\n+// round.\n+func (bft *ProtocolBFTCoSi) startCommitmentPrepare() error {\n+\tcm := bft.prepare.CreateCommitment()\n+\terr := bft.SendTo(bft.Parent(), &Commitment{TYPE: RoundPrepare, Commitment: cm})\n+\tdbg.Lvl3(bft.Name(), \"BFTCoSi Start Commitment PREPARE\")\n+\treturn err\n+}\n+\n+// startCommitCommitment send the first commitment up the tree for the\n+// commitment round.\n+func (bft *ProtocolBFTCoSi) startCommitmentCommit() error {\n+\tcm := bft.commit.CreateCommitment()\n+\n+\terr := bft.SendTo(bft.Parent(), &Commitment{TYPE: RoundCommit, Commitment: cm})\n+\tdbg.Lvl3(bft.Name(), \"BFTCoSi Start Commitment COMMIT\", err)\n+\treturn err\n+}\n+\n+// handle the arrival of a commitment\n+func (bft *ProtocolBFTCoSi) handleCommit(comm Commitment) error {\n+\ttypedCommitment := &Commitment{}\n+\tvar commitment *cosi.Commitment\n+\t// store it and check if we have enough commitments\n+\tswitch comm.TYPE {\n+\tcase RoundPrepare:\n+\t\tbft.tpcMut.Lock()\n+\t\tbft.tempPrepareCommit = append(bft.tempPrepareCommit, comm.Commitment)\n+\t\tif len(bft.tempPrepareCommit) < len(bft.Children()) {\n+\t\t\tbft.tpcMut.Unlock()\n+\t\t\treturn nil\n+\t\t}\n+\t\tcommitment = bft.prepare.Commit(bft.tempPrepareCommit)\n+\t\tbft.tpcMut.Unlock()\n+\t\tif bft.IsRoot() {\n+\t\t\treturn bft.startChallengePrepare()\n+\t\t}\n+\n+\t\tdbg.Lvl3(bft.Name(), \"BFTCoSi handle Commit PREPARE\")\n+\tcase RoundCommit:\n+\t\tbft.tccMut.Lock()\n+\t\tbft.tempCommitCommit = append(bft.tempCommitCommit, comm.Commitment)\n+\t\tif len(bft.tempCommitCommit) < len(bft.Children()) {\n+\t\t\tbft.tccMut.Unlock()\n+\t\t\treturn nil\n+\t\t}\n+\t\tcommitment = bft.commit.Commit(bft.tempCommitCommit)\n+\t\tbft.tccMut.Unlock()\n+\t\tif bft.IsRoot() {\n+\t\t\t// do nothing:\n+\t\t\t// stop the processing of the round, wait the end of\n+\t\t\t// the \"prepare\" round: calls startChallengeCommit\n+\t\t\treturn nil\n+\t\t}\n+\n+\t\tdbg.Lvl3(bft.Name(), \"BFTCoSi handle Commit COMMIT\")\n+\t}\n+\t// set same RoundType as for the received commitment:\n+\ttypedCommitment.TYPE = comm.TYPE\n+\ttypedCommitment.Commitment = commitment\n+\terr := bft.SendTo(bft.Parent(), typedCommitment)\n+\treturn err\n+}\n+\n+// startPrepareChallenge create the challenge and send its down the tree\n+func (bft *ProtocolBFTCoSi) startChallengePrepare() error {\n+\t// create challenge from message's hash:\n+\tprep := &msgPrepare{Msg: bft.Msg}\n+\th := prep.Hash()\n+\tch, err := bft.prepare.CreateChallenge(h)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tbftChal := &ChallengePrepare{\n+\t\tTYPE:      RoundPrepare,\n+\t\tChallenge: ch,\n+\t\tMsg:       bft.Msg,\n+\t}\n+\n+\tgo bft.verificationFun(bft.Msg, bft.verifyChan)\n+\n+\tdbg.Lvl3(bft.Name(), \"BFTCoSi Start Challenge PREPARE\")\n+\t// send to children\n+\tfor _, tn := range bft.Children() {\n+\t\terr = bft.SendTo(tn, bftChal)\n+\t}\n+\treturn err\n+}\n+\n+// startCommitChallenge waits the end of the \"prepare\" round.\n+// Then it creates the challenge and sends it along with the\n+// \"prepare\" signature down the tree.\n+func (bft *ProtocolBFTCoSi) startChallengeCommit() error {\n+\tc, err := bft.commit.CreateChallenge(bft.Msg)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\t// send challenge + signature\n+\tcc := &ChallengeCommit{\n+\t\tTYPE:      RoundCommit,\n+\t\tChallenge: c,\n+\t\tSignature: bft.prepare.Signature(),\n+\t}\n+\tdbg.Lvl3(\"BFTCoSi Start Challenge COMMIT\")\n+\tfor _, tn := range bft.Children() {\n+\t\terr = bft.SendTo(tn, cc)\n+\t}\n+\treturn err\n+}\n+\n+// handlePrepareChallenge receive the challenge messages for the \"prepare\"\n+// round.\n+func (bft *ProtocolBFTCoSi) handleChallengePrepare(ch *ChallengePrepare) error {\n+\tbft.Msg = ch.Msg\n+\t// start the verification of the message\n+\tgo bft.verificationFun(bft.Msg, bft.verifyChan)\n+\t// acknowledge the challenge and send its down\n+\tchal := bft.prepare.Challenge(ch.Challenge)\n+\tch.Challenge = chal\n+\n+\tdbg.Lvl3(bft.Name(), \"BFTCoSi handle Challenge PREPARE\")\n+\t// go to response if leaf\n+\tif bft.IsLeaf() {\n+\t\treturn bft.startResponsePrepare()\n+\t}\n+\tvar err error\n+\tfor _, tn := range bft.Children() {\n+\t\terr = bft.SendTo(tn, ch)","path":"protocols/bftcosi/bftcosi.go","position":379,"original_position":379,"commit_id":"f7e372d4f0f0ecddf30556b3495f5b540096bffc","original_commit_id":"f7e372d4f0f0ecddf30556b3495f5b540096bffc","user":{"login":"ineiti","id":1545067,"avatar_url":"https://avatars.githubusercontent.com/u/1545067?v=3","gravatar_id":"","url":"https://api.github.com/users/ineiti","html_url":"https://github.com/ineiti","followers_url":"https://api.github.com/users/ineiti/followers","following_url":"https://api.github.com/users/ineiti/following{/other_user}","gists_url":"https://api.github.com/users/ineiti/gists{/gist_id}","starred_url":"https://api.github.com/users/ineiti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ineiti/subscriptions","organizations_url":"https://api.github.com/users/ineiti/orgs","repos_url":"https://api.github.com/users/ineiti/repos","events_url":"https://api.github.com/users/ineiti/events{/privacy}","received_events_url":"https://api.github.com/users/ineiti/received_events","type":"User","site_admin":false},"body":"2nd solution, add a `go` in the for-loop of `SendToChildren`","created_at":"2016-04-15T13:26:38Z","updated_at":"2016-04-15T13:26:38Z","html_url":"https://github.com/dedis/cothority/pull/354#discussion_r59873220","pull_request_url":"https://api.github.com/repos/dedis/cothority/pulls/354","_links":{"self":{"href":"https://api.github.com/repos/dedis/cothority/pulls/comments/59873220"},"html":{"href":"https://github.com/dedis/cothority/pull/354#discussion_r59873220"},"pull_request":{"href":"https://api.github.com/repos/dedis/cothority/pulls/354"}}},"pull_request":{"url":"https://api.github.com/repos/dedis/cothority/pulls/354","id":66360439,"html_url":"https://github.com/dedis/cothority/pull/354","diff_url":"https://github.com/dedis/cothority/pull/354.diff","patch_url":"https://github.com/dedis/cothority/pull/354.patch","issue_url":"https://api.github.com/repos/dedis/cothority/issues/354","number":354,"state":"open","locked":false,"title":"Bftcosi","user":{"login":"Liamsi","id":7441766,"avatar_url":"https://avatars.githubusercontent.com/u/7441766?v=3","gravatar_id":"","url":"https://api.github.com/users/Liamsi","html_url":"https://github.com/Liamsi","followers_url":"https://api.github.com/users/Liamsi/followers","following_url":"https://api.github.com/users/Liamsi/following{/other_user}","gists_url":"https://api.github.com/users/Liamsi/gists{/gist_id}","starred_url":"https://api.github.com/users/Liamsi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Liamsi/subscriptions","organizations_url":"https://api.github.com/users/Liamsi/orgs","repos_url":"https://api.github.com/users/Liamsi/repos","events_url":"https://api.github.com/users/Liamsi/events{/privacy}","received_events_url":"https://api.github.com/users/Liamsi/received_events","type":"User","site_admin":false},"body":"related to #348 ","created_at":"2016-04-13T17:31:03Z","updated_at":"2016-04-15T13:26:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3e22e5cc26c78cec65ad41d2570220cb5e72bcf0","assignee":{"login":"Liamsi","id":7441766,"avatar_url":"https://avatars.githubusercontent.com/u/7441766?v=3","gravatar_id":"","url":"https://api.github.com/users/Liamsi","html_url":"https://github.com/Liamsi","followers_url":"https://api.github.com/users/Liamsi/followers","following_url":"https://api.github.com/users/Liamsi/following{/other_user}","gists_url":"https://api.github.com/users/Liamsi/gists{/gist_id}","starred_url":"https://api.github.com/users/Liamsi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Liamsi/subscriptions","organizations_url":"https://api.github.com/users/Liamsi/orgs","repos_url":"https://api.github.com/users/Liamsi/repos","events_url":"https://api.github.com/users/Liamsi/events{/privacy}","received_events_url":"https://api.github.com/users/Liamsi/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/dedis/cothority/pulls/354/commits","review_comments_url":"https://api.github.com/repos/dedis/cothority/pulls/354/comments","review_comment_url":"https://api.github.com/repos/dedis/cothority/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dedis/cothority/issues/354/comments","statuses_url":"https://api.github.com/repos/dedis/cothority/statuses/f7e372d4f0f0ecddf30556b3495f5b540096bffc","head":{"label":"dedis:bftcosi","ref":"bftcosi","sha":"f7e372d4f0f0ecddf30556b3495f5b540096bffc","user":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"repo":{"id":41791684,"name":"cothority","full_name":"dedis/cothority","owner":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dedis/cothority","description":"Scalable collective authority prototype","fork":false,"url":"https://api.github.com/repos/dedis/cothority","forks_url":"https://api.github.com/repos/dedis/cothority/forks","keys_url":"https://api.github.com/repos/dedis/cothority/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dedis/cothority/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dedis/cothority/teams","hooks_url":"https://api.github.com/repos/dedis/cothority/hooks","issue_events_url":"https://api.github.com/repos/dedis/cothority/issues/events{/number}","events_url":"https://api.github.com/repos/dedis/cothority/events","assignees_url":"https://api.github.com/repos/dedis/cothority/assignees{/user}","branches_url":"https://api.github.com/repos/dedis/cothority/branches{/branch}","tags_url":"https://api.github.com/repos/dedis/cothority/tags","blobs_url":"https://api.github.com/repos/dedis/cothority/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dedis/cothority/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dedis/cothority/git/refs{/sha}","trees_url":"https://api.github.com/repos/dedis/cothority/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dedis/cothority/statuses/{sha}","languages_url":"https://api.github.com/repos/dedis/cothority/languages","stargazers_url":"https://api.github.com/repos/dedis/cothority/stargazers","contributors_url":"https://api.github.com/repos/dedis/cothority/contributors","subscribers_url":"https://api.github.com/repos/dedis/cothority/subscribers","subscription_url":"https://api.github.com/repos/dedis/cothority/subscription","commits_url":"https://api.github.com/repos/dedis/cothority/commits{/sha}","git_commits_url":"https://api.github.com/repos/dedis/cothority/git/commits{/sha}","comments_url":"https://api.github.com/repos/dedis/cothority/comments{/number}","issue_comment_url":"https://api.github.com/repos/dedis/cothority/issues/comments{/number}","contents_url":"https://api.github.com/repos/dedis/cothority/contents/{+path}","compare_url":"https://api.github.com/repos/dedis/cothority/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dedis/cothority/merges","archive_url":"https://api.github.com/repos/dedis/cothority/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dedis/cothority/downloads","issues_url":"https://api.github.com/repos/dedis/cothority/issues{/number}","pulls_url":"https://api.github.com/repos/dedis/cothority/pulls{/number}","milestones_url":"https://api.github.com/repos/dedis/cothority/milestones{/number}","notifications_url":"https://api.github.com/repos/dedis/cothority/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dedis/cothority/labels{/name}","releases_url":"https://api.github.com/repos/dedis/cothority/releases{/id}","deployments_url":"https://api.github.com/repos/dedis/cothority/deployments","created_at":"2015-09-02T09:13:57Z","updated_at":"2016-04-08T00:17:26Z","pushed_at":"2016-04-15T13:21:07Z","git_url":"git://github.com/dedis/cothority.git","ssh_url":"git@github.com:dedis/cothority.git","clone_url":"https://github.com/dedis/cothority.git","svn_url":"https://github.com/dedis/cothority","homepage":"","size":52211,"stargazers_count":97,"watchers_count":97,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":7,"mirror_url":null,"open_issues_count":51,"forks":7,"open_issues":51,"watchers":97,"default_branch":"master"}},"base":{"label":"dedis:development","ref":"development","sha":"2d0bae50e608d5bf00281424bb0402967e2319c1","user":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"repo":{"id":41791684,"name":"cothority","full_name":"dedis/cothority","owner":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dedis/cothority","description":"Scalable collective authority prototype","fork":false,"url":"https://api.github.com/repos/dedis/cothority","forks_url":"https://api.github.com/repos/dedis/cothority/forks","keys_url":"https://api.github.com/repos/dedis/cothority/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dedis/cothority/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dedis/cothority/teams","hooks_url":"https://api.github.com/repos/dedis/cothority/hooks","issue_events_url":"https://api.github.com/repos/dedis/cothority/issues/events{/number}","events_url":"https://api.github.com/repos/dedis/cothority/events","assignees_url":"https://api.github.com/repos/dedis/cothority/assignees{/user}","branches_url":"https://api.github.com/repos/dedis/cothority/branches{/branch}","tags_url":"https://api.github.com/repos/dedis/cothority/tags","blobs_url":"https://api.github.com/repos/dedis/cothority/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dedis/cothority/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dedis/cothority/git/refs{/sha}","trees_url":"https://api.github.com/repos/dedis/cothority/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dedis/cothority/statuses/{sha}","languages_url":"https://api.github.com/repos/dedis/cothority/languages","stargazers_url":"https://api.github.com/repos/dedis/cothority/stargazers","contributors_url":"https://api.github.com/repos/dedis/cothority/contributors","subscribers_url":"https://api.github.com/repos/dedis/cothority/subscribers","subscription_url":"https://api.github.com/repos/dedis/cothority/subscription","commits_url":"https://api.github.com/repos/dedis/cothority/commits{/sha}","git_commits_url":"https://api.github.com/repos/dedis/cothority/git/commits{/sha}","comments_url":"https://api.github.com/repos/dedis/cothority/comments{/number}","issue_comment_url":"https://api.github.com/repos/dedis/cothority/issues/comments{/number}","contents_url":"https://api.github.com/repos/dedis/cothority/contents/{+path}","compare_url":"https://api.github.com/repos/dedis/cothority/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dedis/cothority/merges","archive_url":"https://api.github.com/repos/dedis/cothority/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dedis/cothority/downloads","issues_url":"https://api.github.com/repos/dedis/cothority/issues{/number}","pulls_url":"https://api.github.com/repos/dedis/cothority/pulls{/number}","milestones_url":"https://api.github.com/repos/dedis/cothority/milestones{/number}","notifications_url":"https://api.github.com/repos/dedis/cothority/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dedis/cothority/labels{/name}","releases_url":"https://api.github.com/repos/dedis/cothority/releases{/id}","deployments_url":"https://api.github.com/repos/dedis/cothority/deployments","created_at":"2015-09-02T09:13:57Z","updated_at":"2016-04-08T00:17:26Z","pushed_at":"2016-04-15T13:21:07Z","git_url":"git://github.com/dedis/cothority.git","ssh_url":"git@github.com:dedis/cothority.git","clone_url":"https://github.com/dedis/cothority.git","svn_url":"https://github.com/dedis/cothority","homepage":"","size":52211,"stargazers_count":97,"watchers_count":97,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":7,"mirror_url":null,"open_issues_count":51,"forks":7,"open_issues":51,"watchers":97,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dedis/cothority/pulls/354"},"html":{"href":"https://github.com/dedis/cothority/pull/354"},"issue":{"href":"https://api.github.com/repos/dedis/cothority/issues/354"},"comments":{"href":"https://api.github.com/repos/dedis/cothority/issues/354/comments"},"review_comments":{"href":"https://api.github.com/repos/dedis/cothority/pulls/354/comments"},"review_comment":{"href":"https://api.github.com/repos/dedis/cothority/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dedis/cothority/pulls/354/commits"},"statuses":{"href":"https://api.github.com/repos/dedis/cothority/statuses/f7e372d4f0f0ecddf30556b3495f5b540096bffc"}}}}