Skip to content

Commit

Permalink
added quorum validation
Browse files Browse the repository at this point in the history
  • Loading branch information
0xluk committed Feb 8, 2024
1 parent acc8f56 commit b774e5b
Show file tree
Hide file tree
Showing 9 changed files with 1,234 additions and 291 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.20
require (
github.com/cloudflare/circl v1.3.6
github.com/cockroachdb/pebble v1.1.0
github.com/google/go-cmp v0.6.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1
github.com/pkg/errors v0.9.1
github.com/qubic/go-node-connector v0.1.1
Expand Down
2 changes: 1 addition & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg=
github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/fourq v0.0.0-20170427000316-8ada258cf9c8 h1:748sGeXXbplK0UVPDLbhh53hejCnvv/u6jn2RPBfyI8=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
Expand Down Expand Up @@ -135,6 +134,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
Expand Down
207 changes: 207 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package main

import (
"bytes"
"context"
"encoding/binary"
"encoding/hex"
"github.com/cloudflare/circl/xof/k12"
"github.com/pkg/errors"
"github.com/qubic/go-archiver/store"
"github.com/qubic/go-archiver/validation/quorum"
"github.com/qubic/go-node-connector/types"
"go.uber.org/zap"
"log"
"os"
"os/exec"
"strconv"

qubic "github.com/qubic/go-node-connector"

Check failure on line 19 in main.go

View workflow job for this annotation

GitHub Actions / test-nocache (1.21.x, ubuntu-latest)

github.com/qubic/go-node-connector@v0.1.1: replacement directory ../go-qubic does not exist

Check failure on line 19 in main.go

View workflow job for this annotation

GitHub Actions / test-cache

github.com/qubic/go-node-connector@v0.1.1: replacement directory ../go-qubic does not exist

Check failure on line 19 in main.go

View workflow job for this annotation

GitHub Actions / test-nocache (1.21.x, macos-latest)

github.com/qubic/go-node-connector@v0.1.1: replacement directory ../go-qubic does not exist
)

var nodePort = "21841"

func main() {
if len(os.Args) < 2 {
log.Fatalf("Please provide tick number and nodeIP")
}

ip := os.Args[1]

tickNumber, err := strconv.ParseUint(os.Args[2], 10, 64)
if err != nil {
log.Fatalf("Parsing tick number. err: %s", err.Error())
}

err = run(ip, tickNumber)
if err != nil {
log.Fatalf(err.Error())
}
}

func run(nodeIP string, tickNumber uint64) error {
client, err := qubic.NewClient(context.Background(), nodeIP, nodePort)
if err != nil {
log.Fatalf("creating qubic sdk: err: %s", err.Error())
}
// releasing tcp connection related resources
defer client.Close()

logger, _ := zap.NewDevelopment()
verifier := NewVerifier(client, store.NewPebbleStore(nil, logger))
if err := verifier.Verify(context.Background(), tickNumber); err != nil {
return errors.Wrap(err, "verifying tick")
}

return nil
}


func getDigestFromTickData(data types.TickData) ([32]byte, error) {
// xor computor index with 8
data.ComputorIndex ^= 8

sData, err := serializeBinary(data)
if err != nil {
return [32]byte{}, errors.Wrap(err, "serializing data")
}

tickData := sData[:len(sData)-64]
digest, err := hash(tickData)
if err != nil {
return [32]byte{}, errors.Wrap(err, "hashing tick data")
}

return digest, nil
}

func verify(pubkey [32]byte, digest [32]byte, sig [64]byte) error {
pubKeyHex := hex.EncodeToString(pubkey[:])
digestHex := hex.EncodeToString(digest[:])
sigHex := hex.EncodeToString(sig[:])

cmd := exec.Command("./fourq_verify", pubKeyHex, digestHex, sigHex)
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "running fourq_verify cmd: %s", cmd.String())
}

return nil
}

func hash(data []byte) ([32]byte, error) {
h := k12.NewDraft10([]byte{}) // Using K12 for hashing, equivalent to KangarooTwelve(temp, 96, h, 64).
_, err := h.Write(data)
if err != nil {
return [32]byte{}, errors.Wrap(err, "k12 hashing")
}

var out [32]byte
_, err = h.Read(out[:])
if err != nil {
return [32]byte{}, errors.Wrap(err, "reading k12 digest")
}

return out, nil
}

func serializeBinary(data interface{}) ([]byte, error) {
if data == nil {
return nil, nil
}

var buff bytes.Buffer
err := binary.Write(&buff, binary.LittleEndian, data)
if err != nil {
return nil, errors.Wrap(err, "writing data to buff")
}

return buff.Bytes(), nil
}

type Verifier struct {
qu *qubic.Client
store *store.PebbleStore
}

func NewVerifier(qu *qubic.Client, store *store.PebbleStore) *Verifier {
return &Verifier{qu: qu, store: store}
}

func (v *Verifier) Verify(ctx context.Context, tickNumber uint64) error {
computors, err := v.qu.GetComputors(ctx)
if err != nil {
return errors.Wrap(err, "getting computors")
}

arbitratorID := types.Identity(types.ArbitratorIdentity)
arbitratorPubKey, err := arbitratorID.ToPubKey()
if err != nil {
return errors.Wrap(err, "getting arbitrator pubkey")
}

err = validateComputors(computors.Computors, arbitratorPubKey)
if err != nil {
return errors.Wrap(err, "validating computors")
}
log.Println("Computors validated")

quorumTickData, err := v.qu.GetQuorumTickData(ctx, uint32(tickNumber))
if err != nil {
return errors.Wrap(err, "getting quorum tick data")
}

err = quorum.Validate(ctx, quorumTickData, computors.Computors)
if err != nil {
return errors.Wrap(err, "validating quorum")
}

log.Println("Quorum validated")

//tickData, err := v.qu.GetTickData(ctx, uint32(tickNumber))
//if err != nil {
// return errors.Wrap(err, "getting tick data")
//}
//computorPubKey := computors.Computors.PubKeys[tickData.ComputorIndex]
//
//digest, err := getDigestFromTickData(tickData)
//
//// verify tick signature
//err = verify(computorPubKey, digest, tickData.Signature)
//if err != nil {
// return errors.Wrap(err, "verifying tick signature")
//}

return nil
}

func validateComputors(computors types.Computors, arbitratorPubKey [32]byte) error {
digest, err := getDigestFromComputors(computors)
if err != nil {
return errors.Wrap(err, "getting digest from computors")
}

err = verify(arbitratorPubKey, digest, computors.Signature)
if err != nil {
return errors.Wrap(err, "verifying computors signature")
}

return nil
}

func getDigestFromComputors(data types.Computors) ([32]byte, error) {
sData, err := serializeBinary(data)
if err != nil {
return [32]byte{}, errors.Wrap(err, "serializing data")
}

// remove signature from computors data
computorsData := sData[:len(sData)-64]
digest, err := hash(computorsData)
if err != nil {
return [32]byte{}, errors.Wrap(err, "hashing computors data")
}

return digest, nil
}
Loading

0 comments on commit b774e5b

Please sign in to comment.