dedis / d-voting Goto Github PK
View Code? Open in Web Editor NEW📧 E-Voting platform based on the Dela blockchain
Home Page: https://dedis.github.io/d-voting
License: BSD 3-Clause "New" or "Revised" License
📧 E-Voting platform based on the Dela blockchain
Home Page: https://dedis.github.io/d-voting
License: BSD 3-Clause "New" or "Revised" License
To reproduce:
start_test.sh
.setup.sh
untilmemcoin --config /tmp/node1 proxy start --clientaddr 127.0.0.1:8081
<datetime> PNC /path/to/go/pkg/mod/go.dedis.ch/[email protected]/mino/proxy/http/mod.go:108 >
failed to create conn '127.0.0.1:8081': listen tcp 127.0.0.1:8081: bind: address already in use role="http proxy"
panic: failed to create conn '127.0.0.1:8081': listen tcp 127.0.0.1:8081: bind: address already in use
goroutine 438 [running]:
github.com/rs/zerolog.(*Logger).Panic.func1({0xc0000b0d20, 0x0})
/path/to/go/pkg/mod/github.com/rs/[email protected]/log.go:342 +0x2d
github.com/rs/zerolog.(*Event).msg(0xc0004a6c00, {0xc0000b0d20, 0x5f})
/path/to/go/pkg/mod/github.com/rs/[email protected]/event.go:147 +0x2b8
github.com/rs/zerolog.(*Event).Msgf(0xc0004a6c00, {0x1738dc3, 0xc00038a3d0}, {0xc000063f98, 0xc00038a270, 0xc00038a3a8})
/path/to/go/pkg/mod/github.com/rs/[email protected]/event.go:127 +0x4e
go.dedis.ch/dela/mino/proxy/http.(*HTTP).Listen(0xc0000aa3f0)
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/mino/proxy/http/mod.go:108 +0x3be
created by go.dedis.ch/dela/mino/proxy/http/controller.startAction.Execute
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/mino/proxy/http/controller/action.go:28 +0xf4
panic: failed to create conn '127.0.0.1:8081': listen tcp 127.0.0.1:8081: bind: address already in use
goroutine 282 [running]:
github.com/rs/zerolog.(*Logger).Panic.func1({0xc0000430e0, 0x0})
/path/to/go/pkg/mod/github.com/rs/[email protected]/log.go:342 +0x2d
github.com/rs/zerolog.(*Event).msg(0xc000032fc0, {0xc0000430e0, 0x5f})
/path/to/go/pkg/mod/github.com/rs/[email protected]/event.go:147 +0x2b8
github.com/rs/zerolog.(*Event).Msgf(0xc000032fc0, {0x171d6be, 0xc00003e4d0}, {0xc00009ef98, 0x0, 0xc00003e468})
/path/to/go/pkg/mod/github.com/rs/[email protected]/event.go:127 +0x4e
go.dedis.ch/dela/mino/proxy/http.(*HTTP).Listen(0xc0001d6240)
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/mino/proxy/http/mod.go:108 +0x3be
created by go.dedis.ch/dela/mino/proxy/http/controller.startAction.Execute
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/mino/proxy/http/controller/action.go:28 +0xf4
We'd expect it not to crash.
Hi,
As a matter of scalability, I was thinking it made sense to offer the possibility to give a list of scipers who are allowed to vote in a given election. Since the nodes rely on the web backend's signature, it is possible to include it as a requirement for the web backend to sign the tx (is it desirable?).
Similarly, it could be a good idea that the list of admins who can act on the election is given when the election is created (rather than having all admins being able to act on all elections).
To reproduce:
start_test.sh
.setup.sh
untilmemcoin --config /tmp/node1 dkg registerHandlers
panic: http: multiple registrations for /evoting/dkg/init
goroutine 428 [running]:
net/http.(*ServeMux).Handle(0xc000398700, {0x172c58a, 0x11}, {0x17ff200, 0xc000388708})
/usr/local/Cellar/go/1.17.5/libexec/src/net/http/server.go:2441 +0x226
net/http.(*ServeMux).HandleFunc(...)
/usr/local/Cellar/go/1.17.5/libexec/src/net/http/server.go:2478
go.dedis.ch/dela/mino/proxy/http.HTTP.RegisterHandler(...)
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/mino/proxy/http/mod.go:144
github.com/dedis/d-voting/services/dkg/pedersen/controller.(*registerHandlersAction).Execute(0x1722ac8, {{0x18076c0, 0xc00012c418}, {0x18165d8, 0xc00041ae10
}, {0x17fcda0, 0xc00030c040}})
/path/to/EPFL/D-Voting/src/d-voting/services/dkg/pedersen/controller/action.go:355 +0x169
go.dedis.ch/dela/cli/node.(*socketDaemon).handleConn(0xc00015e8f0, {0x181c740, 0xc00030c030})
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/cli/node/daemon.go:185 +0x5e9
created by go.dedis.ch/dela/cli/node.(*socketDaemon).Listen.func2
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/cli/node/daemon.go:129 +0x78
We'd expect the node not to crash.
In the proxy folder, some of the variable names are not consistent.
Where:
proxy/shuffle.go -> EditShuffle
contracts/evoting/evoting.go -> getForm()
Target:
If some ballots are encoded with more chunks of 29 bytes than others, then we could possibly map decrypted ballots to users. They should all have the same size, determined before hand, before the ballot is submitted to the chain
To reproduce:
start_test.sh
.setup.sh
untilmemcoin --config /tmp/node1 e-voting registerHandlers --signer private.key
panic: http: multiple registrations for /evoting/login
goroutine 365 [running]:
net/http.(*ServeMux).Handle(0xc00007e800, {0x172a660, 0xe}, {0x17ff200, 0xc00006a750})
/usr/local/Cellar/go/1.17.5/libexec/src/net/http/server.go:2441 +0x226
net/http.(*ServeMux).HandleFunc(...)
/usr/local/Cellar/go/1.17.5/libexec/src/net/http/server.go:2478
go.dedis.ch/dela/mino/proxy/http.HTTP.RegisterHandler(...)
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/mino/proxy/http/mod.go:144
github.com/dedis/d-voting/contracts/evoting/controller.registerVotingProxy({0x1811068, 0xc0003a25a0}, {0x1811420, 0xc0003524c0}, 0xc0003003c0, {0x18072b0, 0xc00020c540}, {0x18072d8, 0xc000204150}, {0x1810f18, ...}, ...)
/path/to/EPFL/D-Voting/src/d-voting/contracts/evoting/controller/http.go:74 +0x69c
github.com/dedis/d-voting/contracts/evoting/controller.(*registerAction).Execute(0x1722ac8, {{0x18076c0, 0xc00012c418}, {0x18165d8, 0xc00048eb40}, {0x17fcda0, 0xc000010080}})
/path/to/EPFL/D-Voting/src/d-voting/contracts/evoting/controller/action.go:112 +0x616
go.dedis.ch/dela/cli/node.(*socketDaemon).handleConn(0xc00015e8f0, {0x181c740, 0xc000010070})
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/cli/node/daemon.go:185 +0x5e9
created by go.dedis.ch/dela/cli/node.(*socketDaemon).Listen.func2
/path/to/go/pkg/mod/go.dedis.ch/[email protected]/cli/node/daemon.go:129 +0x78
We'd expect the node not to crash.
During the node initialization phase, the master node will run dkg init and collect all the dkgPubKeys to make sure all the keys are the same or the process will fail. However, a malicious node can just always return a false key then will always let the dkg initialization process fail. And right now there is not a monitor system or log to determine which node has the different output thus we are not able to track malicious users.
“services/dkg/pedersen/mod.go” function setup()
The code here will check that all the dkgPubKeys returned from the nodes are the same, and will output false if any of those fails.
Availability
CVSS Score: 4.4/10
The DKG server will proceed to the next phase once it receives more than ⅔ of the correct dkg pubkey.
The DKG server will also report the nodes that return fake keys and raise an alarm to notify there exist some malicious node.
All unit test should have pass.
Add one unit test to test if dkg receives the false dkg public key
When a request to initialize a node is sent, the web backend must redirect it to the correct (i.e the provided) proxy address.
In the proxy folder, some of the functions execute part of the request before verifying the signature. This might have the potential leak with some different msg output. Although most of the errors msg and behavior are publicly accessible in other endpoints (GET) etc without requiring a signature, In general, verifying the signature before executing the request always guarantees better security.
Where:
Proxy/dkg.go -> EditDKGActor()
Proxy/election.go -> EditForm()
Proxy/election.go -> DeleteForm()
Proxy/shuffle.go -> EditShuffle()
Target:
For every request that requires verifying signature in proxy, we should always verify it first before executing the rest of the command.
Before sending the request, we can check for the length of the recipient to decide whether we want to call sendmsg function.
Where:
services/dkg/pedersen/mod.go setup()
Target:
all the unit tests in dkg should pass.
all the functions should be able to work as before.
Whenever the frontend sends an encrypted ballot to the backend to sign, the backend will include the userID of the user in the ballot and sign the msg. This design will allow every user to vote at most once. However, since we are using Tequila as our login server, thus it is hard to create multiple valid users in Tequila during backend testing. A workaround was created. Backend implements a function called “makeID” to create a random ID and sign it along with the encrypted ballot. This will allow a user to vote multiple times which counts as multiple votes. And this function is not yet removed until now. Thus an adversary can vote as many times as he wants to manipulate the election results.
In the file “web/backend/Server.ts” function app.use(‘/api/evoting/*’)
app.use('/api/evoting/*', (req, res) => {
. . .
// special case for voting
const regex = /\/api\/evoting\/elections\/.*\/vote/;
if (req.baseUrl.match(regex)) {
// We must set the UserID to know who this ballot is associated to. This is
// only needed to allow users to cast multiple ballots, where only the last
// ballot is taken into account. To preserve anonymity the web-backend could
// translate UserIDs to another random ID.
// bodyData.UserID = req.session.userid.toString();
bodyData.UserID = makeid(10);
}
function makeid(length: number) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (let i = 0; i < length; i += 1) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
Availability, Auditability
CVSS score: 6.5/10
Remove the makeId function. If the developer prefers to keep the function for testing, we can set an env variable in config.env to determine this environment, which production environment would use User Id and the Dev environment would use Fake Id.
The goal is to remove arbitrary sleep times in the main benchmark code and to watch that a block has been added to the chain before moving on to the next test step.
With the API change, ElectionGetInfo
no longer returns the candidates
. Can be updated at the same time as when we implement the part about election results.
The web backend needs to have a database containing the mapping between the IP address of a node and the IP address of its proxy.
When the frontend makes a GET request on /api/elections/ElectionID/proxies
, the web backend must return the mapping for each node participating in the given election.
It should also be possible to update this mapping by making a POST request (on the same endpoint ?) and giving the new node and proxy addresses.
the shuffler and smart contract will use the ballots' fingerprints as a seed for generating pseudorandomness for the shuffled proof.
However, the fingerprint method will unmarshal all the encrypted ballots and count their hash of them which is not efficient.
We should come out with a more efficient way to calculate the seed for pseudorandomness.
Where:
services/shuffle/neff/handler.go makeTx()
contracts/evoting/evoting.go shuffleBallots()
Why:
To increase the performance of shuffling and verifying proof.
Target:
add a new function to generate seeds for pseudorandomness.
add unit-test that new function.
all unit tests and integration tests should be passed.
When a user wants to cast a ballot, the frontend server will request the election public key from a blockchain node. And the ballot will be encrypted using the public key.
However, if the frontend requests the public key from a compromised blockchain node, the adversary can reply with a fake public key to the user. Then it can decrypt the ballot if the user uses the public key for the encryption.
“web/frontend/src/pages/ballot/Show.tsx” function sendBallot
“pubKey” is derived from the function “web/frontend/src/components/utils/useElection.tsx” to use pctx.getProxy() for the election info.
Confidentiality, Integrity
CVSS Score: 5.8/10
Frontend receives election public keys from at least ⅔ of the nodes.
Frontend reports/sends alert to the D-voting community when releasing there is a different public key.
The DKG return the status Failed when the user tries to setup a node that is already Setup. Currently, the front-end checks during the polling the content of the error message and ignores the error if it contains the string "setup() was already called, only one call is allowed" (marking the Promise as resolved with the status Setup).
An error code, corresponding to this case should be defined instead.
For the moment, the DKG service requires that all the nodes of the roster be initialized to successfully perform the setup. But the system should still work even if some node are not responding (strictly less than 1/3). The following files / block of codes would need to be modified to achieve this:
The DKG service times out with an error if not all the nodes are initialized:
d-voting/services/dkg/pedersen/mod.go
Line 235 in ee2c73d
The status of an election is set to Initial
if one of the node is not initialized:
The election does not got to the status Node Initialized
if one of the node fails to initialize
If some nodes fail to initialize and consensus cannot be reached because of this, only these nodes should retry the initialization (rather than all of them)
If for some reasons some nodes are initialized and others not, the "Initialize" action will send the request to all nodes, including those already initialized. There should be a check to send this request only to non-initialized nodes.
when waiting for the shuffler to reach its shuffle num threshold, the code loop for 10*rosterLen and sleep for roterlen /2 second each time until we received enough amount of round or loop finish. We should change this into using channel along with ctx timeout.
On the other hand, when creating watchCtx waiting times we can use a constant var at the top of the file to increase readability.
Where:
services/shuffle/neff/mod.go waitAndCheckShuffling()
services/shuffle/neff/handler.go handleStartShuffle()
Why:
Increase code readability and reliability.
Target:
all the unit tests in Shuffle should be passed.
all the functions should be able to work as before.
Every request that is signed by the backend will send to the same node as described in config.env.template. However, if the node that is set in the backend env is a malicious node, it can selectively ignore some requests from the backend. For example, it can decide to execute a vote from certain sets of users while ignoring other users' vote that is not on their list.
In the file “web/backend/Server.ts” function sendToDela.
function sendToDela(dataStr: string, req: express.Request, res: express.Response) {
let payload = getPayload(dataStr);
let uri = process.env.DELA_NODE_URL + req.baseUrl.slice(4);
And the value of process.env.DELA_NODE_URL is set to default = “http://localhost:9081/”
In “web/backend/config.env.template”
Availability
CVSS Score: 4.1/10
When creating a form, an operator/admin got a choice to select the “text” option, however the text option maxlength doesn't have a limit, which means a malicious user can create a huge form. And this will increase the load of the node & server when they encoded the cast vote. Since all encrypted ballots should be the same length to avoid leakage, thus the frontend will pad the ballot before the encryption. Thus with a huge form created it will increase the load of the node & server to process the result even if the vote size itself is small. This will potentially be a denial of service attack.
Frontend encoded ballot
// add padding if necessary until encodedBallot.length == ballotSize
if (encodedBallotSize < ballotSize) {
const padding = new ShortUniqueId({ length: ballotSize - encodedBallotSize });
encodedBallot += padding();
}
Availability
CVSS Score: 4.5/10
This can be mitigated by setting a maximum size of ballot for each form.
(Note this will also need to check in the smart contract because we will not trust the request from end-user)
add check-in frontend and smart contract for the maximum length of the form.
add unit-test to test related issue.
There is currently no check on the ballots submitted using the CastVote() command. If a node submits an empty ballot, the problem will be spotted only during the shuffle and the nodes will never be able to proceed.
A unit test has been added in /contracts/evoting/mod_test.go which should fail but currently passes.
To spot the problem, one can replace a casted ballot in the ScenarioTest by a simple CiphterText{}
Fixes to have correct redirection
Under dkg folder, struct Actor and struct dkgHandler both have the function getForm() and all the implementations are the same. Thus we can remove one of the functions or call one function from another to reduce duplication.
Where:
services/dkg/pedersen/mod.go getForm()
services/dkg/pedersen/handler.go getForm()
services/shuffle/neff/mod.go getForm()
Target:
all the unit tests in dkg should pass.
all the unit tests in shuffling should pass.
all the functions should be able to work as before
In general we define that ShuffleThreshold > f, while DKGThreshold > 2f. This is because we only need a shuffler to shuffle 1 time more than the malicious node (f). And for computePubshares, we will need to have more than 2f to protect against the byzantine node.
However, the current system only has “ShuffleThreshold” which didn’t differentiate between “shuffle” and “compute pubshares”. Which will cause problems in the future if we tighten the shuffle threshold.
For checking if we have shuffled enough, we can use shuffleThreshold
contracts/evoting/evoting.go line 396~399
// in case we have enough shuffled ballots, we update the status
if len(form.ShuffleInstances) >= form.ShuffleThreshold {
form.Status = types.ShuffledBallots
PromFormStatus.WithLabelValues(form.FormID).Set(float64(form.Status))
}
But for checking
contracts/evoting/evoting.go line 583~586
if nbrSubmissions >= form.ShuffleThreshold {
form.Status = types.PubSharesSubmitted
PromFormStatus.WithLabelValues(form.FormID).Set(float64(form.Status))
}
Integrity
CVSS Score: 6.6/10
We can create a new threshold “DKGThreshold” for combine Pubshares and only use “ShuffleThreshold” for shuffler related function.
When a casted ballot has been encrypted with a different public key, the decryption process seems to never end. One can add this ballot to the ScenarioTest to simulate this situation (after the three normal ballots have been casted) :
// ###################################### CAST WRONG BALLOT ################
// encrypt a ballot with a different public key:
// TODO with current implementation, the ballot prevents the decryption from ending
RandomStream := suite.RandomStream()
h := suite.Scalar().Pick(RandomStream)
wrongPubKey := suite.Point().Mul(h, nil)
ballot4 := make([]types.Ciphertext, election.ChunksPerBallot())
for i := 0; i < election.ChunksPerBallot(); i++ {
// Embed the message into a curve point
message := "Chunk" + strconv.Itoa(i)
M := suite.Point().Embed([]byte(message), random.New())
// ElGamal-encrypt the point to produce ciphertext (X,Y).
k := suite.Scalar().Pick(random.New()) // ephemeral private key
X := suite.Point().Mul(k, nil) // ephemeral DH public key
S := suite.Point().Mul(k, wrongPubKey) // ephemeral DH shared secret
Y := S.Add(S, M) // message blinded with secret
KMarshalled, _ := X.MarshalBinary()
CMarshalled, _ := Y.MarshalBinary()
ballot4[i] = types.Ciphertext{
K: KMarshalled,
C: CMarshalled,
}
}
castVoteRequest = types.CastVoteRequest{
ElectionID: electionID,
UserID: "user4",
Ballot: ballot4,
Token: token,
}
js, err = json.Marshal(castVoteRequest)
if err != nil {
return xerrors.Errorf("failed to set marshall types.SimpleElection : %v", err)
}
resp, err = http.Post(proxyAddr+castVoteEndpoint, "application/json", bytes.NewBuffer(js))
if err != nil {
return xerrors.Errorf("failed retrieve the decryption from the server: %v", err)
}
if resp.StatusCode != http.StatusOK {
buf, _ := ioutil.ReadAll(resp.Body)
return xerrors.Errorf("unexpected status: %s - %s", resp.Status, buf)
}
body, err = io.ReadAll(resp.Body)
if err != nil {
return xerrors.Errorf("failed to read the body of the response: %v", err)
}
dela.Logger.Info().Msg("Response body : " + string(body))
resp.Body.Close()
// ###################################### CAST WRONG BALLOT ################
What needs to be done is either
web-backend will retrieve the private key and public key when they sign a request. However the public key is not used in this case, thus we can remove it.
Where:
web/backend/src/Server.tx app.delete()
web/backend/src/Server.tx getPayload()
Target:
all functions should have worked as before
pass all related unit tests and integration tests.
The CreateForm struct no requires using AdminID anymore because all the authorizations are now handled in the web-backend. Thus the AdminID in the struct should be removed.
Where:
contracts/evoting/types/transaction.go
type CreateForm struct {
Configuration Configuration
AdminID string
}
Target:
For now, the only requirements of the smart contract to accept the decryptBallots transaction is that it's submitted with the adminId. We should have a way to make sure the decrypted ballots of the transaction are really the result of decrypting the shuffled ballots of the previous state.
We used to Marshall ballot and encrypt in smart contract while do the unit test. but this function is no longer required. Thus we can remove this function.
Where:
services/dkg/pedersen/mod.go Encrypt
Target:
all the unit tests in dkg should pass.
all the unit tests in smart contract should pass.
all the functions should be able to work as before.
Right now the only check we do during the shuffling phase is if we have a threshold of correct shuffling. However, we do not verify that each shuffling comes from a different node. All the shuffling could come from a single node.
Some parts of the code need to rewrite to increase its readability
Where:
services/dkg/pedersen/handler.go handleDecryptRequest() Line 505-519
services/shuffle/neff/handler.go handleStartShufflt() Line 134-148
Target:
all the unit tests in dkg should pass.
all the unit tests in shuffling should pass.
all the functions should be able to work as before.
For now ciphertexts are bounded by Kyber to be <= than 29 bytes. It would be better to represent a cipher text by chunks of 29 bytes. To make sure comparisons between encrypted and decrypted ballots is impossible, the size of all ballots should still be the same
To reproduce:
start_test.sh
.tmux
session, run setup.sh
in the command pane (the one that doesn't have all the logs).memcoin --config /tmp/node1 e-voting scenarioTestPart1
which creates an election. The electionID should be
e8f97378c283218c33dc74ccb120c8677b0c2d6aefa7cc84ef28652862c2f53e
-- if it isn't, the result is the same. It should correspond to the only election on the chain.
memcoin --config /tmp/node1 dkg init --electionID 04
You should get
command error: failed to start the RPC: election 04 does not exist
memcoin --config /tmp/node1 dkg init --electionID 01
You should get no output in that pane, and see in one of the panes:
<datetime> INF services/dkg/pedersen/controller/action.go:98 >
DKG was successfully linked to election [1]
We expected the following error:
command error: failed to start the RPC: election 01 does not exist
In fact, you can try any number of election IDs; some seem to always work, e.g. those ending in 1
and those ending in 9
.
Implementation step of Verifiability Documentation
How:
Update the form struct by adding an array variable to store the hash of encrypted votes.
Update the getForm function to return the hash of encrypted votes.
Where:
contracts/evoting/types/election.go
proxy/election.go getForm()
Target:
edit the unit tests in proxy, and update the getForm unit-test.
edit the unit tests in smart-contract, update the form related unit-test
In the proxy folder, some of the comments in the code are not actually describing the code correctly.
Where:
Proxy/election.go -> NewForm() line 117, comment msg said sign response but it didn’t (should change "sign the response" to "encode the response")
Proxy/election.go -> NewFormVote() line 169, comment msg said encrypt the vote but it didn't (should change this to decode ballot or unmarshal ballot)
Contracts/evoting/types/ciphervote.go line 62, should be "failed to marshal C:"
Target:
The comment should be able to fit what the code trying to achieve.
When using the frontend in the admin section, the system blocks when adding a new user to a role.
This issue to gathers the list of elements that need to be done to release a V1 of D-Voting.
WIP
todo
done
WIP
todo
done
WIP
todo
done
WIP
todo
done
- Adds continuous delivery: build deb package - @nkcr
- Implements ready-to-use docker(-compose) files to deploy a node
Implementation step of Verifiability Documentation
How:
After a user cast a vote and send it to the backend, the frontend will pop up a message (like how you show succeed message after creating an election) showing the hash value (sha256) of the encrypted ballot to the user.
The user can later use that hash value to check if his/her ballot is cast correctly in the blockchain.
Where:
web/frontend/src/
Target:
Users can able to see the hash of the vote.
The hash will only show once.
Users can click a copy icon button to copy the hash of the vote. (optional)
Implementation step of Verifiability Documentation
How:
On the election info page, show a list of the voter who vote and their hash of encrypted votes got from the proxy.
Where:
web/frontend/src/
Target:
Users can view their previously cast votes in the list.
Create paging and search for the user id, since we might have a lot of ballots. (Optional)
We should probably restrict HTTP APIs defined in contracts/evoting/controller
to either POST
/GET
/PUT
depending on the endpoint being invoked.
This might require a change in the frontend as well.
Right now the system decrypts ballot one at a time. This process could be much improved if instead of sending one DKG decrypt request per ballot, we send one decrypt request with all ballots.
If a ballot fails to decrypt during the decryption process, it will return an error and make the whole decryption step fail. This will make the smart contracts will not accept the transaction which means the decryption process will never succeed.
contracts/evoting/evoting.go combineShares()
for j := 0; j < ballotSize; j++ {
chunk, err := decrypt(i, j, allPubShares, form.PubsharesUnits.Indexes)
if err != nil {
return xerrors.Errorf("failed to decrypt (K, C): %v", err)
}
...
}
Availability
CVSS Score: 5.7/10
Ignore the ballot which has a decryption error, just assume it is an empty ballot during the reveal result.
Add some unit-test related to decrypt an error ballot.
The cryptographic function used to encrypt ballots is deterministic, ie. two encryptions of the same ballot will be equal, and the key is public. Therefore using a decrypted ballot it's possible for an attacker to re-encrypt it and see who submitted it. This is a problem only for votations with either few participants or where ballots are mostly unique (eg. with a text question)
Possible mititgations:
When a chain is created, a DKG service is run, and the resulting keypair is to be used for all subsequent elections run on that chain. This means that if the keypair is compromised, many elections could be affected.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.