{"action":"created","comment":{"url":"https://api.github.com/repos/dedis/crypto/pulls/comments/107850213","pull_request_review_id":28051865,"id":107850213,"diff_hunk":"@@ -0,0 +1,611 @@\n+// Package dkg implements the protocol described in\n+// \"Secure Distributed Key Generation for Discrete-Log\n+// Based Cryptosystems\".\n+// DKG enables a group of participants to generate a distributed key\n+// with every participants holding only a share of the key. The key is also\n+// never computed locally but generated distributively whereas the public part\n+// of the key is known by every participants.\n+// The underlying basis for this protocol is the vss protocol implemented in the\n+// share/vss package.\n+//\n+// The protocol works as follow:\n+//  -\n+//  -\n+package dkg\n+\n+import (\n+\t\"bytes\"\n+\t\"crypto/cipher\"\n+\t\"encoding/binary\"\n+\t\"errors\"\n+\t\"fmt\"\n+\n+\t\"github.com/dedis/crypto/abstract\"\n+\t\"github.com/dedis/crypto/share\"\n+\t\"github.com/dedis/crypto/share/vss\"\n+\t\"github.com/dedis/crypto/sign\"\n+)\n+\n+// DistKeyShare holds the share of a distributed key for a participant.\n+type DistKeyShare struct {\n+\t// Coefficients of the public polynomial holding the public key\n+\tCommits []abstract.Point\n+\t// share of the distributed secret\n+\tShare *share.PriShare\n+}\n+\n+// Public returns the public key associated with the distributed private key.\n+func (d *DistKeyShare) Public() abstract.Point {\n+\treturn d.Commits[0]\n+}\n+\n+// Deal holds the Deal for one participants as well as the index of the issuing\n+// Dealer.\n+// NOTE: Doing that in vss.go would be possible but then the Dealer is always\n+// assumed to be a member of the participants. It's only the case here.\n+type Deal struct {\n+\t// Index of the Dealer in the list of participants\n+\tIndex uint32\n+\t// Deal issued for another participant.\n+\tDeal *vss.Deal\n+}\n+\n+// Response holds the Response from another participants as well as the index of\n+// the targeted Dealer.\n+type Response struct {\n+\t// Index of the Dealer for which this response is for\n+\tIndex uint32\n+\t// Response issued from another participant.\n+\tResponse *vss.Response\n+}\n+\n+// Justification holds the Justification from a Dealer as well as the index of\n+// the Dealer in question.\n+type Justification struct {\n+\t// Index of the Dealer who answered with this Justification\n+\tIndex uint32\n+\t// Justification issued from the Dealer.\n+\tJustification *vss.Justification\n+}\n+\n+// SecretCommit is sent during the distributed public key reconstruction phase,\n+// basically a Feldman VSS scheme.\n+type SecretCommits struct {\n+\t// Index of the Dealer in the list of participants\n+\tIndex uint32\n+\t// Commitments generated by the Dealer\n+\tCommitments []abstract.Point\n+\t// SessionID generated by the Dealer tied to the Deal.\n+\tSessionID []byte\n+\t// Signature from the Dealer\n+\tSignature []byte\n+}\n+\n+type ComplaintCommits struct {\n+\t// Index of the Verifier _issuing_ the ComplaintCommit\n+\tIndex uint32\n+\t// DealerIndex being the index of the Dealer who issued the SecretCommits\n+\tDealerIndex uint32\n+\t// Deal that has been given from the Dealer (at DealerIndex) to this node\n+\t// (at Index)\n+\tDeal *vss.Deal\n+\t// Signature made by the verifier\n+\tSignature []byte\n+}\n+\n+// ReconstructCommits holds the information given by a participants who reveals\n+// the deal received from a peer that have received a ComplaintCommits.\n+type ReconstructCommits struct {\n+\t// Index of the verifier who received the deal\n+\tIndex uint32\n+\t// DealerIndex is the index of the dealer who issued the Deal\n+\tDealerIndex uint32\n+\t// Share contained in the Deal\n+\tShare *share.PriShare\n+\t// Signature over all over fields generated by the issuing verifier.\n+\tSignature []byte\n+}\n+\n+type DistKeyGenerator struct {\n+\tsuite abstract.Suite\n+\n+\tindex uint32\n+\tlong  abstract.Scalar\n+\tpub   abstract.Point\n+\n+\tparticipants []abstract.Point\n+\n+\tt int\n+\n+\tdealer    *vss.Dealer\n+\tverifiers map[uint32]*vss.Verifier\n+\n+\t// list of commitments to each secret polynomials\n+\tcommitments map[uint32]*share.PubPoly\n+\n+\t// map of deals collected to reconstruct the full polynomial of a dealer\n+\t// key is index of the dealer. Once there is enough ReconstructCommits\n+\t// struct, the dkg will re-construct the polynomial and stores it into\n+\t// the list of commitments.\n+\tpendingReconstruct map[uint32][]*ReconstructCommits\n+\treconstructed      map[uint32]bool\n+}\n+\n+func NewDistKeyGenerator(suite abstract.Suite, longterm abstract.Scalar, participants []abstract.Point, r cipher.Stream, t int) (*DistKeyGenerator, error) {\n+\td := new(DistKeyGenerator)\n+\tpub := suite.Point().Mul(nil, longterm)\n+\t// find our index\n+\tvar found bool\n+\tfor i, p := range participants {\n+\t\tif p.Equal(pub) {\n+\t\t\tfound = true\n+\t\t\td.index = uint32(i)\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\tif !found {\n+\t\treturn nil, errors.New(\"dkg: own public key not found in list of participants\")\n+\t}\n+\tvar err error\n+\t// generate our dealer / deal\n+\townSec := suite.Scalar().Pick(r)\n+\td.dealer, err = vss.NewDealer(suite, longterm, ownSec, participants, r, t)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\t// to receive the other deals\n+\td.verifiers = make(map[uint32]*vss.Verifier)\n+\td.commitments = make(map[uint32]*share.PubPoly)\n+\td.pendingReconstruct = make(map[uint32][]*ReconstructCommits)\n+\td.reconstructed = make(map[uint32]bool)\n+\td.t = t\n+\td.suite = suite\n+\td.long = longterm\n+\td.pub = pub\n+\td.participants = participants\n+\treturn d, nil\n+}\n+\n+// DistDeals returns all the DistDeal that must be broadcasted to every\n+// participants. The DistDeal corresponding to this DKG is already added\n+// to this DKG and is ommitted from the returned map. To know\n+// to which participant to give the DistDeal, loop over the keys as indexes in\n+// the list of participants:\n+//   for i,dd := range distDeals {\n+//      sendTo(participants[i],dd)\n+//   }\n+// This method panics if it can't process it's own deal.\n+func (d *DistKeyGenerator) Deals() map[int]*Deal {\n+\tdeals := d.dealer.Deals()\n+\tdd := make(map[int]*Deal)\n+\tfor i := range d.participants {\n+\t\tdistd := &Deal{\n+\t\t\tIndex: d.index,\n+\t\t\tDeal:  deals[i],\n+\t\t}\n+\t\tif i == int(d.index) {\n+\t\t\tif resp, err := d.ProcessDeal(distd); err != nil {\n+\t\t\t\tpanic(err)\n+\t\t\t} else if resp.Response.Status != vss.StatusApproval {\n+\t\t\t\tpanic(\"dkg: own deal gave a complaint\")\n+\t\t\t}\n+\t\t\tcontinue\n+\t\t}\n+\t\tdd[i] = distd\n+\t}\n+\treturn dd\n+}\n+\n+// ProcessDeal takes a Deal created by Deals() and store and verifies it. It\n+// returns a Response to broadcast to every other participants. It returns an\n+// error in case the deal has already been stored, or if the deal is incorrect\n+// (see vss.Verifier.ProcessDeal()).\n+func (d *DistKeyGenerator) ProcessDeal(dd *Deal) (*Response, error) {\n+\t// public key of the dealer\n+\tpub, ok := findPub(d.participants, dd.Index)\n+\tif !ok {\n+\t\treturn nil, errors.New(\"dkg: dist deal out of bounds index\")\n+\t}\n+\n+\tif _, ok := d.verifiers[dd.Index]; ok {\n+\t\treturn nil, errors.New(\"dkg: already received dist deal from same index\")\n+\t}\n+\n+\t// verifier receiving the dealer's deal\n+\tver, err := vss.NewVerifier(d.suite, d.long, pub, d.participants)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\td.verifiers[dd.Index] = ver\n+\tresp, err := ver.ProcessDeal(dd.Deal)\n+\treturn &Response{\n+\t\tIndex:    dd.Index,\n+\t\tResponse: resp,\n+\t}, err\n+}\n+\n+// ProcessResponse takes a response from every other peers.  If the response\n+// designates the deal of another participants than this dkg, this dkg stores it\n+// and returns nil with a possible error regarding the validity of the response.\n+// If the response designates a deal this dkg has issued, then the dkg will process\n+// the response, and returns a justification.\n+func (d *DistKeyGenerator) ProcessResponse(resp *Response) (*Justification, error) {\n+\tv, ok := d.verifiers[resp.Index]\n+\tif !ok {\n+\t\treturn nil, errors.New(\"dkg: complaint received but no deal for it\")\n+\t}\n+\n+\tif err := v.ProcessResponse(resp.Response); err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\tif resp.Index != uint32(d.index) {\n+\t\treturn nil, nil\n+\t}\n+\n+\tj, err := d.dealer.ProcessResponse(resp.Response)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tif j == nil {\n+\t\treturn nil, nil\n+\t}\n+\t// a justification for our own deal, are we cheating !?\n+\tif err := v.ProcessJustification(j); err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\treturn &Justification{\n+\t\tIndex:         d.index,\n+\t\tJustification: j,\n+\t}, nil\n+}\n+\n+// ProcessJustification takes a justification and validates it. It returns an\n+// error in case the justification is wrong.\n+func (d *DistKeyGenerator) ProcessJustification(j *Justification) error {\n+\tif v, ok := d.verifiers[j.Index]; !ok {\n+\t\treturn errors.New(\"dkg: Justification received but no deal for it\")\n+\t} else {\n+\t\treturn v.ProcessJustification(j.Justification)\n+\t}\n+}\n+\n+// Certified returns true if at least t deals are certified (see\n+// vss.Verifier.DealCertified()). If the distribution is certified, the protocol\n+// can continue using d.SecretCommits().\n+func (d *DistKeyGenerator) Certified() bool {\n+\treturn len(d.QUAL()) >= d.t\n+}\n+\n+// QUAL returns the index in the list of participants that forms the QUALIFIED\n+// set as described in the \"New-DKG\" protocol by Rabin. Basically, it consists\n+// of all participants that are not disqualified after having  exchanged all\n+// deals, responses and justification. This is the set that is used to extract\n+// the distributed public key with SecretCommits() and ProcessSecretCommits().\n+func (d *DistKeyGenerator) QUAL() []int {\n+\tvar good []int\n+\td.qualIter(func(i uint32, v *vss.Verifier) bool {\n+\t\tgood = append(good, int(i))\n+\t\treturn true\n+\t})\n+\treturn good\n+}\n+\n+func (d *DistKeyGenerator) isInQUAL(idx uint32) bool {\n+\tvar found bool\n+\td.qualIter(func(i uint32, v *vss.Verifier) bool {\n+\t\tif i == idx {\n+\t\t\tfound = true\n+\t\t\treturn false\n+\t\t}\n+\t\treturn true\n+\t})\n+\treturn found\n+}\n+\n+func (d *DistKeyGenerator) qualIter(fn func(idx uint32, v *vss.Verifier) bool) {\n+\tfor i, v := range d.verifiers {\n+\t\tif v.DealCertified() {\n+\t\t\tif !fn(i, v) {\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+// SecretCommits returns the commitments of the coefficients of the secret\n+// polynomials. This secret commits must be broadcasted to every other\n+// participants and must be processed by ProcessSecretCommits. In this manner,\n+// the coefficients are revealed through a Feldman VSS scheme.\n+// This dkg must have its deal certified, otherwise it returns an error. The\n+// SecretCommits returned is already added to this dkg's list of SecretCommits.\n+func (d *DistKeyGenerator) SecretCommits() (*SecretCommits, error) {\n+\tif !d.dealer.DealCertified() {\n+\t\treturn nil, errors.New(\"dkg: can't give SecretCommits if deal not certified\")\n+\t}\n+\tsc := &SecretCommits{\n+\t\tCommitments: d.dealer.Commits(),\n+\t\tIndex:       uint32(d.index),\n+\t\tSessionID:   d.dealer.SessionID(),\n+\t}\n+\tmsg := sc.Hash(d.suite)\n+\tsig, err := sign.Schnorr(d.suite, d.long, msg)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tsc.Signature = sig\n+\t// adding our own commitments\n+\td.commitments[uint32(d.index)] = share.NewPubPoly(d.suite, d.suite.Point().Base(), sc.Commitments)\n+\treturn sc, err\n+}\n+\n+// ProcessSecretCommits takes a SecretCommits from every other participants and\n+// verifies and stores it. It returns an error in case the SecretCommits is\n+// invalid. In case the SecretCommits are valid, but this dkg can't verify its\n+// share, it returns a ComplaintCommits that must be broadcasted to every other\n+// participants. In returns nil,nil otherwise.\n+func (d *DistKeyGenerator) ProcessSecretCommits(sc *SecretCommits) (*ComplaintCommits, error) {\n+\tpub, ok := findPub(d.participants, sc.Index)\n+\tif !ok {\n+\t\treturn nil, errors.New(\"dkg: secretcommits received with index out of bounds\")\n+\t}\n+\n+\tif !d.isInQUAL(sc.Index) {\n+\t\treturn nil, errors.New(\"dkg: secretcommits from a non QUAL member\")\n+\t}\n+\n+\t// mapping verified by isInQUAL\n+\tv := d.verifiers[sc.Index]\n+\n+\tif !bytes.Equal(v.SessionID(), sc.SessionID) {\n+\t\treturn nil, errors.New(\"dkg: secretcommits received with wrong session id\")\n+\t}\n+\n+\tmsg := sc.Hash(d.suite)\n+\tif err := sign.VerifySchnorr(d.suite, pub, msg, sc.Signature); err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\tdeal := v.Deal()\n+\tpoly := share.NewPubPoly(d.suite, d.suite.Point().Base(), sc.Commitments)\n+\tif !poly.Check(deal.SecShare) {\n+\t\tcc := &ComplaintCommits{\n+\t\t\tIndex:       uint32(d.index),\n+\t\t\tDealerIndex: sc.Index,\n+\t\t\tDeal:        deal,\n+\t\t}\n+\t\tvar err error\n+\t\tmsg := cc.Hash(d.suite)\n+\t\tif cc.Signature, err = sign.Schnorr(d.suite, d.long, msg); err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t\treturn cc, nil\n+\t}\n+\t// commitments are fine\n+\td.commitments[sc.Index] = poly\n+\treturn nil, nil\n+}\n+\n+// ProcessComplaintCommits takes any ComplaintCommits revealed through\n+// ProcessSecretCommits() from other participants in QUAL. It returns the\n+// ReconstructCommits message that must be  broadcasted to every other participants\n+// in QUAL so the polynomial in question can be reconstructed.\n+func (d *DistKeyGenerator) ProcessComplaintCommits(cc *ComplaintCommits) (*ReconstructCommits, error) {\n+\tissuer, ok := findPub(d.participants, cc.Index)\n+\tif !ok {\n+\t\treturn nil, errors.New(\"dkg: commitcomplaint with unknown issuer\")\n+\t}\n+\n+\tif !d.isInQUAL(cc.Index) {\n+\t\treturn nil, errors.New(\"dkg: complaintcommit from non-qual member\")\n+\t}\n+\n+\tif err := sign.VerifySchnorr(d.suite, issuer, cc.Hash(d.suite), cc.Signature); err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\tv, ok := d.verifiers[cc.DealerIndex]\n+\tif !ok {\n+\t\treturn nil, errors.New(\"dkg: commitcomplaint linked to unknown verifier\")\n+\t}\n+\n+\t// the verification should pass for the deal, and not with the secret\n+\t// commits. Verification 4) in DKG Rabin's paper.\n+\tif err := v.VerifyDeal(cc.Deal, false); err != nil {\n+\t\treturn nil, fmt.Errorf(\"dkg: verifying deal: %s\", err)\n+\t}\n+\n+\tsecretCommits, ok := d.commitments[cc.DealerIndex]\n+\tif !ok {\n+\t\treturn nil, errors.New(\"dkg: complaint about non received commitments\")\n+\t}\n+\n+\t// the secret commits check should fail. Verification 5) in DKG Rabin's\n+\t// paper.\n+\tif secretCommits.Check(cc.Deal.SecShare) {\n+\t\treturn nil, errors.New(\"dkg: invalid complaint, deal verifying\")\n+\t}\n+\n+\tdeal := v.Deal()\n+\tif deal == nil {\n+\t\treturn nil, errors.New(\"dkg: complaint linked to non certified deal\")\n+\t}\n+\n+\tdelete(d.commitments, cc.DealerIndex)\n+\trc := &ReconstructCommits{\n+\t\tIndex:       d.index,\n+\t\tDealerIndex: cc.DealerIndex,\n+\t\tShare:       deal.SecShare,\n+\t}\n+\n+\tmsg := rc.Hash(d.suite)\n+\tvar err error\n+\trc.Signature, err = sign.Schnorr(d.suite, d.long, msg)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\td.pendingReconstruct[cc.DealerIndex] = append(d.pendingReconstruct[cc.DealerIndex], rc)\n+\treturn rc, nil\n+}\n+\n+// ProcessReconstructCommits takes a ReconstructCommits message and stores it\n+// along any others. If there is enough message to recover the coefficients of\n+// the public polynomials of the malicious dealer in question, then the\n+// polynomial is recovered.\n+func (d *DistKeyGenerator) ProcessReconstructCommits(rs *ReconstructCommits) error {\n+\tif _, ok := d.reconstructed[rs.DealerIndex]; ok {\n+\t\t// commitments already reconstructed, no need for other shares\n+\t\treturn nil\n+\t}\n+\t_, ok := d.commitments[rs.DealerIndex]\n+\tif ok {\n+\t\treturn errors.New(\"dkg: commitments not invalidated by any complaints\")\n+\t}\n+\n+\tpub, ok := findPub(d.participants, rs.Index)\n+\tif !ok {\n+\t\treturn errors.New(\"dkg: reconstruct commits with invalid verifier index\")\n+\t}\n+\n+\tmsg := rs.Hash(d.suite)\n+\tif err := sign.VerifySchnorr(d.suite, pub, msg, rs.Signature); err != nil {\n+\t\treturn err\n+\t}\n+\n+\tvar arr = d.pendingReconstruct[rs.DealerIndex]\n+\t// check if packet is already received or not\n+\tfor _, r := range arr {\n+\t\tif r.Index == rs.Index {\n+\t\t\t// no-op ? error ?\n+\t\t\treturn nil\n+\t\t}\n+\t}\n+\t// add it to list of pending\n+\tarr = append(arr, rs)\n+\td.pendingReconstruct[rs.DealerIndex] = arr\n+\t// check if we can reconstruct commitments\n+\tif len(arr) >= d.t {\n+\t\tvar shares = make([]*share.PriShare, 0, len(arr))\n+\t\tfor _, r := range arr {\n+\t\t\tshares = append(shares, r.Share)","path":"share/dkg/dkg.go","position":493,"original_position":492,"commit_id":"dd6620ca2544bb6b9e03f71600f22fd2db672470","original_commit_id":"cc2b36fa175983ab0b154ce595fb4ebb8f6044ad","user":{"login":"ineiti","id":1545067,"avatar_url":"https://avatars1.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":"style: `shares[i] = r.Share`?","created_at":"2017-03-24T07:53:54Z","updated_at":"2017-03-24T07:59:31Z","html_url":"https://github.com/dedis/crypto/pull/130#discussion_r107850213","pull_request_url":"https://api.github.com/repos/dedis/crypto/pulls/130","_links":{"self":{"href":"https://api.github.com/repos/dedis/crypto/pulls/comments/107850213"},"html":{"href":"https://github.com/dedis/crypto/pull/130#discussion_r107850213"},"pull_request":{"href":"https://api.github.com/repos/dedis/crypto/pulls/130"}}},"pull_request":{"url":"https://api.github.com/repos/dedis/crypto/pulls/130","id":111520542,"html_url":"https://github.com/dedis/crypto/pull/130","diff_url":"https://github.com/dedis/crypto/pull/130.diff","patch_url":"https://github.com/dedis/crypto/pull/130.patch","issue_url":"https://api.github.com/repos/dedis/crypto/issues/130","number":130,"state":"open","locked":false,"title":"[Share] Distributed Key Generation protocol implementation (6/7)","user":{"login":"nikkolasg","id":2564747,"avatar_url":"https://avatars1.githubusercontent.com/u/2564747?v=3","gravatar_id":"","url":"https://api.github.com/users/nikkolasg","html_url":"https://github.com/nikkolasg","followers_url":"https://api.github.com/users/nikkolasg/followers","following_url":"https://api.github.com/users/nikkolasg/following{/other_user}","gists_url":"https://api.github.com/users/nikkolasg/gists{/gist_id}","starred_url":"https://api.github.com/users/nikkolasg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikkolasg/subscriptions","organizations_url":"https://api.github.com/users/nikkolasg/orgs","repos_url":"https://api.github.com/users/nikkolasg/repos","events_url":"https://api.github.com/users/nikkolasg/events{/privacy}","received_events_url":"https://api.github.com/users/nikkolasg/received_events","type":"User","site_admin":false},"body":"This PR brings the Distributed Key Generation protocol by Rabin. \r\nThe basic idea is:\r\n - every participants create and share a secret with every one else\r\n - after this steps, everyone reveals its public polynomial to create the distributed public key and verify each share.\r\n\r\nIt's currently against `share_vss2` but once the latter gets merged, must be changed to be against master.","created_at":"2017-03-20T10:15:13Z","updated_at":"2017-03-24T07:59:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"492434a290aa1fdc0ad7d555424f3891bd29c386","assignee":{"login":"nikkolasg","id":2564747,"avatar_url":"https://avatars1.githubusercontent.com/u/2564747?v=3","gravatar_id":"","url":"https://api.github.com/users/nikkolasg","html_url":"https://github.com/nikkolasg","followers_url":"https://api.github.com/users/nikkolasg/followers","following_url":"https://api.github.com/users/nikkolasg/following{/other_user}","gists_url":"https://api.github.com/users/nikkolasg/gists{/gist_id}","starred_url":"https://api.github.com/users/nikkolasg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikkolasg/subscriptions","organizations_url":"https://api.github.com/users/nikkolasg/orgs","repos_url":"https://api.github.com/users/nikkolasg/repos","events_url":"https://api.github.com/users/nikkolasg/events{/privacy}","received_events_url":"https://api.github.com/users/nikkolasg/received_events","type":"User","site_admin":false},"assignees":[{"login":"nikkolasg","id":2564747,"avatar_url":"https://avatars1.githubusercontent.com/u/2564747?v=3","gravatar_id":"","url":"https://api.github.com/users/nikkolasg","html_url":"https://github.com/nikkolasg","followers_url":"https://api.github.com/users/nikkolasg/followers","following_url":"https://api.github.com/users/nikkolasg/following{/other_user}","gists_url":"https://api.github.com/users/nikkolasg/gists{/gist_id}","starred_url":"https://api.github.com/users/nikkolasg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikkolasg/subscriptions","organizations_url":"https://api.github.com/users/nikkolasg/orgs","repos_url":"https://api.github.com/users/nikkolasg/repos","events_url":"https://api.github.com/users/nikkolasg/events{/privacy}","received_events_url":"https://api.github.com/users/nikkolasg/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/dedis/crypto/pulls/130/commits","review_comments_url":"https://api.github.com/repos/dedis/crypto/pulls/130/comments","review_comment_url":"https://api.github.com/repos/dedis/crypto/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dedis/crypto/issues/130/comments","statuses_url":"https://api.github.com/repos/dedis/crypto/statuses/dd6620ca2544bb6b9e03f71600f22fd2db672470","head":{"label":"dedis:share_dkg","ref":"share_dkg","sha":"dd6620ca2544bb6b9e03f71600f22fd2db672470","user":{"login":"dedis","id":3638331,"avatar_url":"https://avatars1.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":25253455,"name":"crypto","full_name":"dedis/crypto","owner":{"login":"dedis","id":3638331,"avatar_url":"https://avatars1.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/crypto","description":"Advanced crypto library for the Go language","fork":false,"url":"https://api.github.com/repos/dedis/crypto","forks_url":"https://api.github.com/repos/dedis/crypto/forks","keys_url":"https://api.github.com/repos/dedis/crypto/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dedis/crypto/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dedis/crypto/teams","hooks_url":"https://api.github.com/repos/dedis/crypto/hooks","issue_events_url":"https://api.github.com/repos/dedis/crypto/issues/events{/number}","events_url":"https://api.github.com/repos/dedis/crypto/events","assignees_url":"https://api.github.com/repos/dedis/crypto/assignees{/user}","branches_url":"https://api.github.com/repos/dedis/crypto/branches{/branch}","tags_url":"https://api.github.com/repos/dedis/crypto/tags","blobs_url":"https://api.github.com/repos/dedis/crypto/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dedis/crypto/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dedis/crypto/git/refs{/sha}","trees_url":"https://api.github.com/repos/dedis/crypto/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dedis/crypto/statuses/{sha}","languages_url":"https://api.github.com/repos/dedis/crypto/languages","stargazers_url":"https://api.github.com/repos/dedis/crypto/stargazers","contributors_url":"https://api.github.com/repos/dedis/crypto/contributors","subscribers_url":"https://api.github.com/repos/dedis/crypto/subscribers","subscription_url":"https://api.github.com/repos/dedis/crypto/subscription","commits_url":"https://api.github.com/repos/dedis/crypto/commits{/sha}","git_commits_url":"https://api.github.com/repos/dedis/crypto/git/commits{/sha}","comments_url":"https://api.github.com/repos/dedis/crypto/comments{/number}","issue_comment_url":"https://api.github.com/repos/dedis/crypto/issues/comments{/number}","contents_url":"https://api.github.com/repos/dedis/crypto/contents/{+path}","compare_url":"https://api.github.com/repos/dedis/crypto/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dedis/crypto/merges","archive_url":"https://api.github.com/repos/dedis/crypto/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dedis/crypto/downloads","issues_url":"https://api.github.com/repos/dedis/crypto/issues{/number}","pulls_url":"https://api.github.com/repos/dedis/crypto/pulls{/number}","milestones_url":"https://api.github.com/repos/dedis/crypto/milestones{/number}","notifications_url":"https://api.github.com/repos/dedis/crypto/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dedis/crypto/labels{/name}","releases_url":"https://api.github.com/repos/dedis/crypto/releases{/id}","deployments_url":"https://api.github.com/repos/dedis/crypto/deployments","created_at":"2014-10-15T12:25:03Z","updated_at":"2017-02-19T03:57:44Z","pushed_at":"2017-03-23T10:43:51Z","git_url":"git://github.com/dedis/crypto.git","ssh_url":"git@github.com:dedis/crypto.git","clone_url":"https://github.com/dedis/crypto.git","svn_url":"https://github.com/dedis/crypto","homepage":"","size":5503,"stargazers_count":80,"watchers_count":80,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":20,"mirror_url":null,"open_issues_count":24,"forks":20,"open_issues":24,"watchers":80,"default_branch":"master"}},"base":{"label":"dedis:share_vss2","ref":"share_vss2","sha":"bf98fa600fc2e907b6fc2ddc4842dc8229925653","user":{"login":"dedis","id":3638331,"avatar_url":"https://avatars1.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":25253455,"name":"crypto","full_name":"dedis/crypto","owner":{"login":"dedis","id":3638331,"avatar_url":"https://avatars1.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/crypto","description":"Advanced crypto library for the Go language","fork":false,"url":"https://api.github.com/repos/dedis/crypto","forks_url":"https://api.github.com/repos/dedis/crypto/forks","keys_url":"https://api.github.com/repos/dedis/crypto/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dedis/crypto/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dedis/crypto/teams","hooks_url":"https://api.github.com/repos/dedis/crypto/hooks","issue_events_url":"https://api.github.com/repos/dedis/crypto/issues/events{/number}","events_url":"https://api.github.com/repos/dedis/crypto/events","assignees_url":"https://api.github.com/repos/dedis/crypto/assignees{/user}","branches_url":"https://api.github.com/repos/dedis/crypto/branches{/branch}","tags_url":"https://api.github.com/repos/dedis/crypto/tags","blobs_url":"https://api.github.com/repos/dedis/crypto/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dedis/crypto/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dedis/crypto/git/refs{/sha}","trees_url":"https://api.github.com/repos/dedis/crypto/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dedis/crypto/statuses/{sha}","languages_url":"https://api.github.com/repos/dedis/crypto/languages","stargazers_url":"https://api.github.com/repos/dedis/crypto/stargazers","contributors_url":"https://api.github.com/repos/dedis/crypto/contributors","subscribers_url":"https://api.github.com/repos/dedis/crypto/subscribers","subscription_url":"https://api.github.com/repos/dedis/crypto/subscription","commits_url":"https://api.github.com/repos/dedis/crypto/commits{/sha}","git_commits_url":"https://api.github.com/repos/dedis/crypto/git/commits{/sha}","comments_url":"https://api.github.com/repos/dedis/crypto/comments{/number}","issue_comment_url":"https://api.github.com/repos/dedis/crypto/issues/comments{/number}","contents_url":"https://api.github.com/repos/dedis/crypto/contents/{+path}","compare_url":"https://api.github.com/repos/dedis/crypto/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dedis/crypto/merges","archive_url":"https://api.github.com/repos/dedis/crypto/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dedis/crypto/downloads","issues_url":"https://api.github.com/repos/dedis/crypto/issues{/number}","pulls_url":"https://api.github.com/repos/dedis/crypto/pulls{/number}","milestones_url":"https://api.github.com/repos/dedis/crypto/milestones{/number}","notifications_url":"https://api.github.com/repos/dedis/crypto/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dedis/crypto/labels{/name}","releases_url":"https://api.github.com/repos/dedis/crypto/releases{/id}","deployments_url":"https://api.github.com/repos/dedis/crypto/deployments","created_at":"2014-10-15T12:25:03Z","updated_at":"2017-02-19T03:57:44Z","pushed_at":"2017-03-23T10:43:51Z","git_url":"git://github.com/dedis/crypto.git","ssh_url":"git@github.com:dedis/crypto.git","clone_url":"https://github.com/dedis/crypto.git","svn_url":"https://github.com/dedis/crypto","homepage":"","size":5503,"stargazers_count":80,"watchers_count":80,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":20,"mirror_url":null,"open_issues_count":24,"forks":20,"open_issues":24,"watchers":80,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dedis/crypto/pulls/130"},"html":{"href":"https://github.com/dedis/crypto/pull/130"},"issue":{"href":"https://api.github.com/repos/dedis/crypto/issues/130"},"comments":{"href":"https://api.github.com/repos/dedis/crypto/issues/130/comments"},"review_comments":{"href":"https://api.github.com/repos/dedis/crypto/pulls/130/comments"},"review_comment":{"href":"https://api.github.com/repos/dedis/crypto/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dedis/crypto/pulls/130/commits"},"statuses":{"href":"https://api.github.com/repos/dedis/crypto/statuses/dd6620ca2544bb6b9e03f71600f22fd2db672470"}}}}
{"actor":{"display_login":"ineiti"}}