From 61b03b21deb7a4b2f543e9cce3be4c604a8a7692 Mon Sep 17 00:00:00 2001 From: huangzhiran Date: Wed, 24 Dec 2025 17:01:02 +0800 Subject: [PATCH] impl sum proof --- service/apinode/aggregator/aggregator.go | 2 +- service/apinode/api/http.go | 38 +++++++---- vm/payload.go | 80 ++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 14 deletions(-) diff --git a/service/apinode/aggregator/aggregator.go b/service/apinode/aggregator/aggregator.go index 270aef75..97a87b83 100644 --- a/service/apinode/aggregator/aggregator.go +++ b/service/apinode/aggregator/aggregator.go @@ -47,7 +47,7 @@ func Run(projectManager *project.Manager, db *apidb.DB, sequencerAddr string, in slog.Error("failed to get project config", "error", err, "project_id", pid) continue } - if cfg.ProofType == "movement" { + if cfg.ProofType == "movement" || cfg.ProofType == "sum" { prevTaskID := tasks[0].TaskID tasks[len(tasks)-1].PrevTaskID = prevTaskID } diff --git a/service/apinode/api/http.go b/service/apinode/api/http.go index 64e70d48..45194940 100644 --- a/service/apinode/api/http.go +++ b/service/apinode/api/http.go @@ -170,19 +170,31 @@ func (s *httpServer) createTask(c *gin.Context) { var matchedPubkey *ecdsa.PublicKey var approved bool for _, r := range recovered { - addr := crypto.PubkeyToAddress(*r.pubkey) - slog.Debug("recovered address", "project_id", req.ProjectID, "address", addr.String()) - ok, err := s.db.IsDeviceApproved(req.ProjectID, addr) - if err != nil { - slog.Error("failed to check device permission", "error", err) - c.JSON(http.StatusInternalServerError, newErrResp(errors.Wrap(err, "failed to check device permission"))) - return - } - if ok { - approved = true - matchedPubkey = r.pubkey - sig = r.sig - break + if req.ProjectID == "9" { + addr := crypto.PubkeyToAddress(*r.pubkey) + slog.Debug("recovered address", "project_id", req.ProjectID, "address", addr.String()) + ok, err := s.db.IsDeviceApproved(req.ProjectID, addr) + if err != nil { + slog.Error("failed to check device permission", "error", err) + c.JSON(http.StatusInternalServerError, newErrResp(errors.Wrap(err, "failed to check device permission"))) + return + } + if ok { + approved = true + matchedPubkey = r.pubkey + sig = r.sig + break + } + } else { + addr := crypto.PubkeyToAddress(*r.pubkey) + deviceAddr := gjson.GetBytes(req.Payload, "address").Str + + if strings.EqualFold(addr.Hex(), deviceAddr) { + approved = true + matchedPubkey = r.pubkey + sig = r.sig + break + } } } if !approved { diff --git a/vm/payload.go b/vm/payload.go index 3ded143e..6e98c105 100644 --- a/vm/payload.go +++ b/vm/payload.go @@ -20,6 +20,8 @@ func loadPayload(tasks []*task.Task, projectConfig *project.Config) ([]byte, err return encodeLivenessPayload(tasks[0], projectConfig) case "movement": return encodeMovementPayload(tasks, projectConfig) + case "sum": + return encodeSumPayload(tasks, projectConfig) default: return tasks[0].Payload, nil } @@ -168,3 +170,81 @@ func abs(a, b uint64) uint64 { } return b - a } + +const SumMaxItems = 2 + +type ProofOfSumCircuit struct { + PayloadHashs [SumMaxItems][32]uints.U8 + Timestamps [SumMaxItems]frontend.Variable + Values [SumMaxItems]frontend.Variable + SigBytes [SumMaxItems][64]uints.U8 + + PubBytes [SumMaxItems][65]uints.U8 + StartTime frontend.Variable + + Threshold frontend.Variable `gnark:",public"` + EthAddress frontend.Variable `gnark:",public"` +} + +func (circuit *ProofOfSumCircuit) Define(api frontend.API) error { return nil } + +func encodeSumPayload(tasks []*task.Task, projectConfig *project.Config) ([]byte, error) { + if len(tasks) != 1 { + return nil, errors.Errorf("invalid tasks len, expect %d, get %d", 1, len(tasks)) + } + assignment := ProofOfSumCircuit{} + task := tasks[0] + if task.PrevTask == nil { + return nil, errors.New("sum project miss previous task") + } + lastPayloadHash, _, _, lastData, err := api.HashTask( + &api.CreateTaskReq{ + Nonce: task.PrevTask.Nonce, + ProjectID: task.PrevTask.ProjectID.String(), + ProjectVersion: task.PrevTask.ProjectVersion, + Payload: task.PrevTask.Payload, + }, projectConfig) + if err != nil { + return nil, err + } + curPayloadHash, _, _, curData, err := api.HashTask( + &api.CreateTaskReq{ + Nonce: task.Nonce, + ProjectID: task.ProjectID.String(), + ProjectVersion: task.ProjectVersion, + Payload: task.Payload, + }, projectConfig) + if err != nil { + return nil, err + } + lastTimestamp := lastData[0].(uint64) + lastValue := lastData[1].(uint64) + lastSig := task.PrevTask.Signature[:64] + curTimestamp := curData[0].(uint64) + curValue := curData[1].(uint64) + curSig := task.Signature[:64] + + assignment.PayloadHashs[0] = [32]uints.U8(uints.NewU8Array(lastPayloadHash[:])) + assignment.Timestamps[0] = lastTimestamp + assignment.Values[0] = lastValue + assignment.SigBytes[0] = [64]uints.U8(uints.NewU8Array(lastSig[:])) + assignment.PayloadHashs[1] = [32]uints.U8(uints.NewU8Array(curPayloadHash[:])) + assignment.Timestamps[1] = curTimestamp + assignment.Values[1] = curValue + assignment.SigBytes[1] = [64]uints.U8(uints.NewU8Array(curSig[:])) + assignment.PubBytes[0] = [65]uints.U8(uints.NewU8Array(task.DevicePubKey)) + assignment.PubBytes[1] = [65]uints.U8(uints.NewU8Array(task.DevicePubKey)) + assignment.Threshold = uint64(10) + + pubkey, err := crypto.UnmarshalPubkey(task.DevicePubKey) + if err != nil { + return nil, errors.Wrap(err, "failed to unmarshal pubkey") + } + assignment.EthAddress = crypto.PubkeyToAddress(*pubkey).Big() + + witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + if err != nil { + return nil, err + } + return witness.MarshalBinary() +}