3 Commits
v0.0.2 ... main

Author SHA1 Message Date
arnaucube
9a5be110fc Updt Sequencer errormsg on try_contr on 200ok code 2023-01-14 23:31:21 +01:00
arnaucube
1c95590ba0 Update VerifySRS (SRS/State)
Update/split VerifySRS into verifying new SRS from prev SRS, and
verifying the obtained State from the Sequencer (which includes proofs &
last SRS)
2023-01-14 22:41:48 +01:00
arnaucube
9a50ec9e43 Update queue waiting logic 2023-01-14 10:14:13 +01:00
5 changed files with 167 additions and 55 deletions

View File

@@ -19,6 +19,9 @@ Documents used for this implementation:
- [KZG10-Ceremony-audit-report.pdf, section *3.1 Overview of PoT ceremonies*](https://github.com/ethereum/kzg-ceremony/blob/main/KZG10-Ceremony-audit-report.pdf)
- [*Why and how zkSNARKs work*, by Maksym Petkus](https://arxiv.org/abs/1906.07221v1)
**You can find more info on the logic behind the powers of tau computation & verification in these notes: http://arnaucube.com/blog/powersoftau.html**
### Usage
Get the binary from the [releases](https://github.com/arnaucube/eth-kzg-ceremony-alt/releases) (alternative you can compile it from source), and run:
```
@@ -28,9 +31,9 @@ eth-kzg-ceremony-alt
====================
Usage of ./kzgceremony:
-u, --url string sequencer url (default "https://kzg-ceremony-sequencer-dev.fly.dev")
-r, --rand string randomness
-s, --sleeptime uint time (seconds) sleeping before trying again to be the next contributor (default 10)
-u, --url string sequencer url (default "https://seq.ceremony.ethereum.org")
-r, --rand string randomness, needs to be bigger than 64 bytes
-s, --sleeptime uint time (seconds) sleeping before trying again to be the next contributor (default 30)
```
So for example, run your contribution with:

View File

@@ -7,6 +7,7 @@ import (
"io"
"io/ioutil"
"net/http"
"strings"
kzgceremony "github.com/arnaucube/eth-kzg-ceremony-alt"
)
@@ -132,38 +133,59 @@ func (c *Client) PostAuthCallback() (*MsgRequestLink, error) {
return &msg, err
}
func (c *Client) PostTryContribute(sessionID string) (*kzgceremony.BatchContribution, bool, error) {
type Status int
const (
StatusReauth = Status(iota)
StatusError
StatusWait
StatusProceed
)
func (c *Client) PostTryContribute(sessionID string) (*kzgceremony.BatchContribution, Status, error) {
bearer := "Bearer " + sessionID
resp, err := c.postWithAuth(
c.url+"/lobby/try_contribute", "application/json", nil, bearer)
if err != nil {
return nil, false, err
return nil, StatusError, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, false, err
return nil, StatusError, err
}
if resp.StatusCode != http.StatusOK {
fmt.Println(string(body))
switch resp.StatusCode {
case http.StatusBadRequest:
return nil, true, fmt.Errorf("call came to early. rate limited")
return nil, StatusWait, fmt.Errorf("call came to early. rate limited")
case http.StatusUnauthorized:
return nil, false, fmt.Errorf("unkown session id. unauthorized access")
return nil, StatusReauth, fmt.Errorf("unkown session id. unauthorized access")
default:
return nil, false, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
return nil, StatusWait, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
}
}
// note: a 200 (Ok) code by the Sequencer on try_contribute doesn't
// mean that the contributor has been selected. It could mean that the
// Sequencer is returning the error AnotherContributionInProgress in a
// json msg (see
// https://github.com/ethereum/kzg-ceremony-sequencer/blob/2538f2f08d4db880d7f4608e964df0b695bc7d2f/src/api/v1/error_response.rs#L105
// )
// check if body contains the error message of "another contribution in
// progress" (despite http statuscode being 200 (Ok))
if strings.Contains(string(body), "another contribution in progress") {
return nil, StatusWait, fmt.Errorf("another contribution in progress")
}
err = ioutil.WriteFile("prevBatchContribution.json", body, 0600)
if err != nil {
return nil, false, err
return nil, StatusError, err
}
bc := &kzgceremony.BatchContribution{}
err = json.Unmarshal(body, bc)
return bc, false, err
return bc, StatusProceed, err
}
func (c *Client) PostAbortContribution(sessionID string) ([]byte, error) {

View File

@@ -15,26 +15,29 @@ import (
flag "github.com/spf13/pflag"
)
var (
red = color.New(color.FgRed)
redB = color.New(color.FgRed, color.Bold)
cyan = color.New(color.FgCyan)
cyanB = color.New(color.FgCyan, color.Bold)
green = color.New(color.FgHiGreen)
greenB = color.New(color.FgHiGreen, color.Bold)
)
func main() {
fmt.Println("eth-kzg-ceremony-alt")
fmt.Printf("====================\n")
fmt.Printf(" https://github.com/arnaucube/eth-kzg-ceremony-alt\n\n")
redB := color.New(color.FgRed, color.Bold)
cyan := color.New(color.FgCyan)
cyanB := color.New(color.FgCyan, color.Bold)
green := color.New(color.FgHiGreen)
greenB := color.New(color.FgHiGreen, color.Bold)
var sequencerURL string
var randomness string
var sleepTime uint64
flag.StringVarP(&sequencerURL, "url", "u",
"https://sequencer.ceremony.ethereum.org", "sequencer url")
"https://seq.ceremony.ethereum.org", "sequencer url")
flag.StringVarP(&randomness, "rand", "r",
"", fmt.Sprintf("randomness, needs to be bigger than %d", kzgceremony.MinRandomnessLen))
"", fmt.Sprintf("randomness, needs to be bigger than %d bytes", kzgceremony.MinRandomnessLen))
flag.Uint64VarP(&sleepTime, "sleeptime", "s",
10, "time (seconds) sleeping before trying again to be the next contributor")
30, "time (seconds) sleeping before trying again to be the next contributor")
flag.CommandLine.SortFlags = false
flag.Parse()
@@ -61,25 +64,8 @@ func main() {
}
// Auth
msgReqLink, err := c.GetRequestLink()
if err != nil {
printErrAndExit(err)
}
_, _ = green.Printf("Please go to\n%s\n and authenticate with Github.\n", msgReqLink.GithubAuthURL)
fmt.Println("(currently only Github auth is supported)")
_, _ = greenB.Printf("Paste here the RawData from the auth answer:\n")
s, err := readInput()
if err != nil {
printErrAndExit(err)
}
var authMsg client.MsgAuthCallback
if err = json.Unmarshal([]byte(s), &authMsg); err != nil {
printErrAndExit(err)
}
fmt.Print("Parsed auth msg: ")
_, _ = cyan.Printf("%#v\n", authMsg)
fmt.Println("Github Authorization:")
authMsg := authGH(c)
// TODO this will be only triggered by a flag
// msg, err := c.PostAbortContribution(authMsg.SessionID)
@@ -94,16 +80,27 @@ func main() {
var prevBatchContribution *kzgceremony.BatchContribution
for {
fmt.Printf("%s sending try_contribute\n", time.Now().Format("2006-01-02 15:04:05"))
var retry bool
prevBatchContribution, retry, err = c.PostTryContribute(authMsg.SessionID)
var status client.Status
prevBatchContribution, status, err = c.PostTryContribute(authMsg.SessionID)
if err != nil {
_, _ = cyan.Println(err)
}
if !retry {
if status == client.StatusProceed {
break
}
fmt.Printf("%s try_contribute unsuccessful, going to sleep %d seconds\n",
time.Now().Format("2006-01-02 15:04:05"), sleepTime)
if status == client.StatusReauth {
fmt.Println("SessionID has expired, authenticate again with Github:")
authMsg = authGH(c)
}
msgStatus, err := c.GetCurrentStatus()
if err != nil {
printErrAndExit(err)
}
fmt.Printf("%s try_contribute unsuccessful, lobby size %d, num contrib %d,"+
"\n going to sleep %d seconds\n",
time.Now().Format("2006-01-02 15:04:05"),
msgStatus.LobbySize, msgStatus.NumContributions,
sleepTime)
time.Sleep(time.Duration(sleepTime) * time.Second)
}
@@ -115,19 +112,25 @@ func main() {
// }
fmt.Println("starting to compute new contribution")
t0 := time.Now()
newBatchContribution, err := prevBatchContribution.Contribute([]byte(randomness))
if err != nil {
fmt.Println("error on prevBatchContribution.Contribute")
printErrAndExit(err)
}
fmt.Println("Contribution computed in", time.Since(t0))
// store contribution
fmt.Println("storing contribution.json")
b, err := json.Marshal(newBatchContribution)
if err != nil {
printErrAndExit(err)
// print error but do not exit
_, _ = red.Println(err)
}
err = ioutil.WriteFile("contribution.json", b, 0600)
if err != nil {
printErrAndExit(err)
// print error but do not exit
_, _ = red.Println(err)
}
// send contribution
@@ -151,8 +154,30 @@ func main() {
}
}
func authGH(c *client.Client) client.MsgAuthCallback {
msgReqLink, err := c.GetRequestLink()
if err != nil {
printErrAndExit(err)
}
_, _ = green.Printf("Please go to\n%s\n and authenticate with Github.\n", msgReqLink.GithubAuthURL)
fmt.Println("(currently only Github auth is supported)")
_, _ = greenB.Printf("Paste here the RawData from the auth answer:\n")
s, err := readInput()
if err != nil {
printErrAndExit(err)
}
var authMsg client.MsgAuthCallback
if err = json.Unmarshal([]byte(s), &authMsg); err != nil {
printErrAndExit(err)
}
fmt.Print("Parsed auth msg: ")
_, _ = cyan.Printf("%#v\n", authMsg)
return authMsg
}
func printErrAndExit(err error) {
red := color.New(color.FgRed)
_, _ = red.Println(err)
os.Exit(1)
}

View File

@@ -138,7 +138,7 @@ func newEmptySRS(nG1, nG2 int) *SRS {
}
func tau(round int, randomness []byte) *toxicWaste {
val := blake2b.Sum256(randomness)
val := blake2b.Sum256(append(randomness, byte(round)))
tau := new(big.Int).Mod(
new(big.Int).SetBytes(val[:]),
g2.Q())
@@ -181,7 +181,8 @@ func genProof(toxicWaste *toxicWaste, prevSRS, newSRS *SRS) *Proof {
// byte slice, and returns the new SRS together with the Proof
func Contribute(prevSRS *SRS, round int, randomness []byte) (*SRS, *Proof, error) {
if len(randomness) < MinRandomnessLen {
return nil, nil, fmt.Errorf("err randomness") // WIP
return nil, nil, fmt.Errorf("err: randomness length < %d",
MinRandomnessLen)
}
// set tau from randomness
tw := tau(round, randomness)
@@ -231,9 +232,10 @@ func checkG2PointCorrectness(p *bls12381.PointG2) error {
return nil
}
// Verify checks the correct computation of the new SRS respectively from the
// previous SRS
func Verify(prevSRS, newSRS *SRS, proof *Proof) bool {
// VerifyNewSRSFromPrevSRS checks the correct computation of the new SRS
// respectively from the previous SRS. These are the checks that the Sequencer
// would do.
func VerifyNewSRSFromPrevSRS(prevSRS, newSRS *SRS, proof *Proof) bool {
pairing := bls12381.NewEngine()
// 1. check that elements of the newSRS are valid points
@@ -282,3 +284,58 @@ func Verify(prevSRS, newSRS *SRS, proof *Proof) bool {
return true
}
// VerifyState acts similarly to VerifyNewSRSFromPrevSRS, but verifying the
// given State (which can be obtained from the Sequencer)
func VerifyState(s *State) bool {
pairing := bls12381.NewEngine()
for _, t := range s.Transcripts {
// 1. check that elements of the SRS are valid points
for i := 0; i < len(t.PowersOfTau.G1Powers); i++ {
if err := checkG1PointCorrectness(t.PowersOfTau.G1Powers[i]); err != nil {
return false
}
}
for i := 0; i < len(t.PowersOfTau.G2Powers); i++ {
if err := checkG2PointCorrectness(t.PowersOfTau.G2Powers[i]); err != nil {
return false
}
}
// 2. check t.Witness.RunningProducts[last] == t.PowersOfTau.G1Powers[1]
if !g1.Equal(t.Witness.RunningProducts[len(t.Witness.RunningProducts)-1],
t.PowersOfTau.G1Powers[1]) {
return false
}
// 3. check newSRS.G1s[1] (g₁^τ'), is correctly related to prevSRS.G1s[1] (g₁^τ)
// e([τ]₁, [p]₂) == e([τ']₁, [1]₂)
eL := pairing.AddPair(t.Witness.RunningProducts[len(t.Witness.RunningProducts)-2], t.Witness.PotPubKeys[len(t.Witness.PotPubKeys)-1]).Result()
eR := pairing.AddPair(t.Witness.RunningProducts[len(t.Witness.RunningProducts)-1], g2.One()).Result()
if !eL.Equal(eR) {
return false
}
// 4. check newSRS following the powers of tau structure
for i := 0; i < len(t.PowersOfTau.G1Powers)-1; i++ {
// i) e([τ'ⁱ]₁, [τ']₂) == e([τ'ⁱ⁺¹]₁, [1]₂), for i ∈ [1, n1]
eL := pairing.AddPair(t.PowersOfTau.G1Powers[i], t.PowersOfTau.G2Powers[1]).Result()
eR := pairing.AddPair(t.PowersOfTau.G1Powers[i+1], g2.One()).Result()
if !eL.Equal(eR) {
return false
}
}
for i := 0; i < len(t.PowersOfTau.G2Powers)-1; i++ {
// ii) e([τ']₁, [τ'ʲ]₂) == e([1]₁, [τ'ʲ⁺¹]₂), for j ∈ [1, m1]
eL := pairing.AddPair(t.PowersOfTau.G1Powers[1], t.PowersOfTau.G2Powers[i]).Result()
eR := pairing.AddPair(g1.One(), t.PowersOfTau.G2Powers[i+1]).Result()
if !eL.Equal(eR) {
return false
}
}
}
return true
}

View File

@@ -17,12 +17,12 @@ func TestContribution(t *testing.T) {
[]byte("1111111111111111111111111111111111111111111111111111111111111111"))
c.Assert(err, qt.IsNil)
c.Assert(Verify(srs_0, srs_1, proof_1), qt.IsTrue)
c.Assert(VerifyNewSRSFromPrevSRS(srs_0, srs_1, proof_1), qt.IsTrue)
srs_2, proof_2, err := Contribute(srs_1, 0,
[]byte("2222222222222222222222222222222222222222222222222222222222222222"))
c.Assert(err, qt.IsNil)
c.Assert(Verify(srs_1, srs_2, proof_2), qt.IsTrue)
c.Assert(VerifyNewSRSFromPrevSRS(srs_1, srs_2, proof_2), qt.IsTrue)
}
func TestComputeNewState(t *testing.T) {
@@ -57,6 +57,11 @@ func TestBatchContribution(t *testing.T) {
bc.Contribute([]byte("1111111111111111111111111111111111111111111111111111111111111111"))
c.Assert(err, qt.IsNil)
c.Assert(len(nb.Contributions), qt.Equals, 4)
c.Assert(g2.Equal(nb.Contributions[0].PotPubKey, nb.Contributions[1].PotPubKey), qt.IsFalse)
c.Assert(g2.Equal(nb.Contributions[0].PotPubKey, nb.Contributions[2].PotPubKey), qt.IsFalse)
c.Assert(g2.Equal(nb.Contributions[0].PotPubKey, nb.Contributions[3].PotPubKey), qt.IsFalse)
_, err = json.Marshal(nb)
c.Assert(err, qt.IsNil)
}