Skip to content

Commit fd87a2e

Browse files
committed
add signature and proof verification
1 parent d0e870e commit fd87a2e

File tree

2 files changed

+88
-22
lines changed

2 files changed

+88
-22
lines changed

rust/catalyst-voting/src/txs/v1/decoding.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ const PUBLIC_VOTE_TAG: u8 = 1;
2828
const WITNESS_TAG: u8 = 2;
2929

3030
impl Tx {
31-
/// Write the bytes to sign for the `Tx` to provided `buf`.
31+
/// Write the bytes of the `Tx` body to provided `buf`.
3232
#[allow(clippy::cast_possible_truncation)]
33-
pub(super) fn bytes_to_sign(
33+
pub(super) fn tx_body_decode(
3434
vote_plan_id: &[u8; 32], proposal_index: u8, vote: &VotePayload, public_key: &PublicKey,
3535
buf: &mut Vec<u8>,
3636
) {
@@ -73,25 +73,25 @@ impl Tx {
7373
#[allow(clippy::cast_possible_truncation)]
7474
pub fn to_bytes(&self) -> Vec<u8> {
7575
// Initialize already with the padding tag `0` and fragment tag `11`.
76-
let mut tx_body = vec![PADDING_TAG, FRAGMENT_TAG];
76+
let mut buf = vec![PADDING_TAG, FRAGMENT_TAG];
7777

78-
Self::bytes_to_sign(
78+
Self::tx_body_decode(
7979
&self.vote_plan_id,
8080
self.proposal_index,
8181
&self.vote,
8282
&self.public_key,
83-
&mut tx_body,
83+
&mut buf,
8484
);
8585

86-
// Input tag
87-
tx_body.push(WITNESS_TAG);
86+
// Witness tag
87+
buf.push(WITNESS_TAG);
8888
// Zero nonce
89-
tx_body.extend_from_slice(&[0u8; 4]);
90-
tx_body.extend_from_slice(&self.signature.to_bytes());
89+
buf.extend_from_slice(&[0u8; 4]);
90+
buf.extend_from_slice(&self.signature.to_bytes());
9191

9292
// Add the size of decoded bytes to the beginning.
93-
let mut res = (tx_body.len() as u32).to_be_bytes().to_vec();
94-
res.append(&mut tx_body);
93+
let mut res = (buf.len() as u32).to_be_bytes().to_vec();
94+
res.append(&mut buf);
9595
res
9696
}
9797

rust/catalyst-voting/src/txs/v1/mod.rs

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,20 @@
3838
3939
mod decoding;
4040

41+
use anyhow::ensure;
4142
use rand_core::CryptoRngCore;
4243

4344
use crate::{
4445
crypto::{
4546
default_rng,
46-
ed25519::{sign, PrivateKey, PublicKey, Signature},
47+
ed25519::{sign, verify_signature, PrivateKey, PublicKey, Signature},
4748
hash::{digest::Digest, Blake2b256Hasher, Blake2b512Hasher},
4849
},
4950
vote_protocol::{
5051
committee::ElectionPublicKey,
5152
voter::{
5253
encrypt_vote_with_default_rng,
53-
proof::{generate_voter_proof, VoterProof, VoterProofCommitment},
54+
proof::{generate_voter_proof, verify_voter_proof, VoterProof, VoterProofCommitment},
5455
EncryptedVote, Vote,
5556
},
5657
},
@@ -154,22 +155,64 @@ impl Tx {
154155
})
155156
}
156157

158+
/// Verify transaction signature and underlying proof for public vote
159+
///
160+
/// # Errors
161+
/// - Invalid signature
162+
/// - Invalid proof
163+
pub fn verify(&self, election_public_key: &ElectionPublicKey) -> anyhow::Result<()> {
164+
let bytes = Self::bytes_to_sign(
165+
&self.vote_plan_id,
166+
self.proposal_index,
167+
&self.vote,
168+
&self.public_key,
169+
);
170+
ensure!(
171+
verify_signature(&self.public_key, &bytes, &self.signature),
172+
"Invalid signature."
173+
);
174+
175+
if let VotePayload::Private(encrypted_vote, proof) = &self.vote {
176+
let vote_plan_id_hash = Blake2b512Hasher::new().chain_update(self.vote_plan_id);
177+
let commitment = VoterProofCommitment::from_hash(vote_plan_id_hash);
178+
ensure!(
179+
verify_voter_proof(
180+
encrypted_vote.clone(),
181+
election_public_key,
182+
&commitment,
183+
proof,
184+
),
185+
"Invalid proof."
186+
);
187+
}
188+
189+
Ok(())
190+
}
191+
157192
/// Generate transaction signature
158193
fn sign(
159194
vote_plan_id: &[u8; 32], proposal_index: u8, vote: &VotePayload, private_key: &PrivateKey,
160195
) -> Signature {
161-
let mut bytes = Vec::new();
162-
Self::bytes_to_sign(
196+
let bytes = Self::bytes_to_sign(
163197
vote_plan_id,
164198
proposal_index,
165199
vote,
166200
&private_key.public_key(),
167-
&mut bytes,
168201
);
169-
let msg = Blake2b256Hasher::new()
202+
sign(private_key, &bytes)
203+
}
204+
205+
/// Generate bytes to be signed.
206+
/// A Blake2b256 hash of the transaction body
207+
fn bytes_to_sign(
208+
vote_plan_id: &[u8; 32], proposal_index: u8, vote: &VotePayload, public_key: &PublicKey,
209+
) -> Vec<u8> {
210+
let mut bytes = Vec::new();
211+
Self::tx_body_decode(vote_plan_id, proposal_index, vote, public_key, &mut bytes);
212+
Blake2b256Hasher::new()
170213
.chain_update(bytes.as_slice())
171-
.finalize();
172-
sign(private_key, msg.as_slice())
214+
.finalize()
215+
.to_vec()
173216
}
174217
}
175218

@@ -205,6 +248,27 @@ impl VotePayload {
205248

206249
Ok(Self::Private(encrypted_vote, voter_proof))
207250
}
251+
252+
// #[allow(clippy::cast_possible_truncation, dead_code)]
253+
// fn choice(&self, secret_key: &ElectionSecretKey) -> anyhow::Result<u8> {
254+
// match self {
255+
// Self::Public(choice) => Ok(*choice),
256+
// Self::Private(vote, _) => {
257+
// // Making a tally and decryption tally procedure on one vote to retrieve
258+
// the // original voting choice.
259+
// // Assuming that the voting power argument must be equals to 1.
260+
// let setup = DecryptionTallySetup::new(1)?;
261+
// for voting_option in 0..vote.voting_options() {
262+
// let tally = tally(voting_option, &[vote.clone()], &[1])?;
263+
// let choice_for_voting_option = decrypt_tally(&tally, secret_key,
264+
// &setup)?; if choice_for_voting_option == 1 {
265+
// return Ok(voting_option as u8);
266+
// }
267+
// }
268+
// bail!("Invalid encrypted vote, not a unit vector");
269+
// },
270+
// }
271+
// }
208272
}
209273

210274
#[cfg(test)]
@@ -216,22 +280,23 @@ mod tests {
216280

217281
#[proptest]
218282
fn tx_test(
219-
vote_plan_id: [u8; 32], proposal_index: u8, #[strategy(1u8..)] voting_options: u8,
283+
vote_plan_id: [u8; 32], proposal_index: u8, #[strategy(1u8..5)] voting_options: u8,
220284
#[strategy(0..#voting_options)] choice: u8, users_private_key: PrivateKey,
221285
election_secret_key: ElectionSecretKey,
222286
) {
223287
let election_public_key = election_secret_key.public_key();
224288

225-
let _tx = Tx::new_public(
289+
let tx = Tx::new_public(
226290
vote_plan_id,
227291
proposal_index,
228292
voting_options,
229293
choice,
230294
&users_private_key,
231295
)
232296
.unwrap();
297+
tx.verify(&election_public_key).unwrap();
233298

234-
let _tx = Tx::new_private_with_default_rng(
299+
let tx = Tx::new_private_with_default_rng(
235300
vote_plan_id,
236301
proposal_index,
237302
voting_options,
@@ -240,5 +305,6 @@ mod tests {
240305
&users_private_key,
241306
)
242307
.unwrap();
308+
tx.verify(&election_public_key).unwrap();
243309
}
244310
}

0 commit comments

Comments
 (0)