From db11d328292744f7b6823391a56507c4d663c354 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Tue, 15 Oct 2024 23:33:11 +0300 Subject: [PATCH] container: add container placement verification The new `VerifyPlacementSignatures` checks if a message was signed by a suitable number of nodes. Number is taken from the contract storage, their relevance should be ensured and maintained by the Alphabet nodes every epoch. Closes #413. Signed-off-by: Pavel Karpy --- contracts/container/config.yml | 2 +- contracts/container/contract.go | 42 +++++++++++++++ contracts/container/contract.nef | Bin 8037 -> 8438 bytes contracts/container/manifest.json | 2 +- rpc/container/rpcbinding.go | 5 ++ tests/container_test.go | 85 ++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 2 deletions(-) diff --git a/contracts/container/config.yml b/contracts/container/config.yml index 95c62cd8..4cd139a9 100644 --- a/contracts/container/config.yml +++ b/contracts/container/config.yml @@ -1,5 +1,5 @@ name: "NeoFS Container" -safemethods: ["alias", "count", "containersOf", "get", "owner", "list", "nodes", "replicasNumbers", "eACL", "getContainerSize", "listContainerSizes", "iterateContainerSizes", "iterateAllContainerSizes", "version"] +safemethods: ["alias", "count", "containersOf", "get", "owner", "list", "nodes", "replicasNumbers", "verifyPlacementSignatures", "eACL", "getContainerSize", "listContainerSizes", "iterateContainerSizes", "iterateAllContainerSizes", "version"] permissions: - methods: ["update", "addKey", "transferX", "register", "registerTLD", "addRecord", "deleteRecords", "subscribeForNewEpoch"] diff --git a/contracts/container/contract.go b/contracts/container/contract.go index 64b58435..f74dcde1 100644 --- a/contracts/container/contract.go +++ b/contracts/container/contract.go @@ -582,6 +582,48 @@ func validatePlacementIndex(ctx storage.Context, cID interop.Hash256, inx uint8) } } +// VerifyPlacementSignatures verifies that message has been signed by container +// members according to container's placement policy: there should be at least +// REP number of signatures for every placement vector. sigs must be container's +// number of SELECTs length. +func VerifyPlacementSignatures(cid interop.Hash256, msg []byte, sigs [][]interop.Signature, curveHash crypto.NamedCurveHash) bool { + sigsLen := len(sigs) + var i int + repsI := ReplicasNumbers(cid) +repsLoop: + for iterator.Next(repsI) { + if sigsLen == i { + panic("not found signatures for " + std.Itoa10(i) + " placement vector") + } + + m := iterator.Value(repsI).(int) + if len(sigs[i]) < m { + panic("not enough signatures for " + std.Itoa10(i) + " placement vector, required: " + std.Itoa10(m)) + } + + var counter int + for _, sig := range sigs[i] { + pubsI := Nodes(cid, uint8(i)) + for iterator.Next(pubsI) { + pub := iterator.Value(pubsI).(interop.PublicKey) + if crypto.VerifyWithECDsa(msg, pub, sig, curveHash) { + counter++ + break + } + } + + if counter == m { + i++ + continue repsLoop + } + } + + panic("verified " + std.Itoa10(counter) + " signatures for " + std.Itoa10(i) + " placement vector, required: " + std.Itoa10(m)) + } + + return true +} + // CommitContainerListUpdate commits container list changes made by // [AddNextEpochNodes] calls in advance. Replicas must correspond to // ordered placement policy (REP clauses). If no [AddNextEpochNodes] diff --git a/contracts/container/contract.nef b/contracts/container/contract.nef index aee3607136686749585a2c009a1d8218e07e5233..8917311a979831bf712d4df0763ff3d26641ad4d 100755 GIT binary patch delta 615 zcmaEA_swyF8zbLF_ic=V{AH;{nQ4{bnI##n&Mw7?ERz!$#V7w|6lB^Zw^@KmfP=|P zWU~@i5)+f4z~(j{E+(d3{F5i~B{F^B-TakLgOTYX?__xa8>aWXlP3r$O|BQ4I2&oePFl;wfFpr)J$b%p`Z83yI-mHF(s)gk6Q3~KB- zb4rvlS(I+(WNUF{&M9q#qao-5tR$jG}{UX~9?P1ch;#I)<#EN_%Ic>n-S=GwRb delta 235 zcmez7_|$HK8zb*V_ic=mRha~t0%bQ_FbQxlJrvsP#g)Xww1RK*Ivy@2ra->QyZ92B z+Icq1@@p_MW$;XP7qDS!SsWf@H06$YOgn3I~CDRP9&8>nn3D`2T-l zrm4V}%@0Kdm^oj+{r|r-*Yx{`$-g8Nn7ZCimXVyz;GEd$wqqtd5wvmyM cXY&R*J|H!Dzx*L4