diff --git a/rust/catalyst-voting/Cargo.toml b/rust/catalyst-voting/Cargo.toml index 2c23a9165d..6f0c4609ff 100644 --- a/rust/catalyst-voting/Cargo.toml +++ b/rust/catalyst-voting/Cargo.toml @@ -24,10 +24,13 @@ curve25519-dalek = { version = "4.1.3", features = ["digest", "rand_core"] } ed25519-dalek = { version = "2.1.1", features = ["rand_core"] } blake2b_simd = "1.0.2" rayon = "1.10.0" +minicbor = { version = "0.25.1", features = ["alloc", "derive", "half"] } + +cbork-utils = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "cbork-utils-v0.0.2" } [dev-dependencies] criterion = "0.5.1" -proptest = { version = "1.5.0" } +proptest = { version = "1.6.0", features = ["attr-macro"] } # Potentially it could be replaced with using `proptest::property_test` attribute macro, # after this PR will be merged https://github.com/proptest-rs/proptest/pull/523 test-strategy = "0.4.0" diff --git a/rust/catalyst-voting/src/crypto/elgamal/decoding.rs b/rust/catalyst-voting/src/crypto/elgamal/decoding.rs index 52e207f84c..8a97e41393 100644 --- a/rust/catalyst-voting/src/crypto/elgamal/decoding.rs +++ b/rust/catalyst-voting/src/crypto/elgamal/decoding.rs @@ -1,6 +1,8 @@ //! Elgamal objects decoding implementation use anyhow::anyhow; +use cbork_utils::decode_helper::decode_array_len; +use minicbor::{Decode, Decoder, Encode, Encoder, encode::Write}; use super::{Ciphertext, GroupElement}; @@ -34,6 +36,35 @@ impl Ciphertext { } } +impl Encode<()> for Ciphertext { + fn encode( + &self, + e: &mut Encoder, + ctx: &mut (), + ) -> Result<(), minicbor::encode::Error> { + e.array(2)?; + self.0.encode(e, ctx)?; + self.1.encode(e, ctx) + } +} + +impl Decode<'_, ()> for Ciphertext { + fn decode( + d: &mut Decoder<'_>, + ctx: &mut (), + ) -> Result { + let len = decode_array_len(d, "Ciphertext")?; + if len != 2 { + return Err(minicbor::decode::Error::message(format!( + "Unexpected Ciphertext array length: {len}, expected 2" + ))); + } + let c1 = GroupElement::decode(d, ctx)?; + let c2 = GroupElement::decode(d, ctx)?; + Ok(Self(c1, c2)) + } +} + #[cfg(test)] mod tests { use test_strategy::proptest; @@ -46,4 +77,14 @@ mod tests { let c2 = Ciphertext::from_bytes(&bytes).unwrap(); assert_eq!(c1, c2); } + + #[proptest] + fn cbor_roundtrip(original: Ciphertext) { + let mut buffer = Vec::new(); + original + .encode(&mut Encoder::new(&mut buffer), &mut ()) + .unwrap(); + let decoded = Ciphertext::decode(&mut Decoder::new(&buffer), &mut ()).unwrap(); + assert_eq!(original, decoded); + } } diff --git a/rust/catalyst-voting/src/crypto/elgamal/mod.rs b/rust/catalyst-voting/src/crypto/elgamal/mod.rs index f11f2cf3bf..0f65ebad97 100644 --- a/rust/catalyst-voting/src/crypto/elgamal/mod.rs +++ b/rust/catalyst-voting/src/crypto/elgamal/mod.rs @@ -8,7 +8,15 @@ use std::ops::{Add, Mul}; use crate::crypto::group::{GroupElement, Scalar}; /// `ElGamal` ciphertext, encrypted message with the public key. -#[derive(Debug, Clone, PartialEq, Eq)] +/// +/// The CBOR CDDL schema: +/// ```cddl +/// elgamal-ristretto255-encrypted-choice = [ +/// c1: elgamal-ristretto255-group-element +/// c2: elgamal-ristretto255-group-element +/// ] +/// ``` +#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[must_use] pub struct Ciphertext(GroupElement, GroupElement); @@ -19,6 +27,14 @@ impl Ciphertext { Ciphertext(GroupElement::zero(), GroupElement::zero()) } + /// Creates a `Ciphertext` instance from the given elements. + pub fn from_elements( + first: GroupElement, + second: GroupElement, + ) -> Self { + Self(first, second) + } + /// Get the first element of the `Ciphertext`. pub fn first(&self) -> &GroupElement { &self.0 diff --git a/rust/catalyst-voting/src/crypto/group/ristretto255/decoding.rs b/rust/catalyst-voting/src/crypto/group/ristretto255/decoding.rs index a577d84abe..f7019af581 100644 --- a/rust/catalyst-voting/src/crypto/group/ristretto255/decoding.rs +++ b/rust/catalyst-voting/src/crypto/group/ristretto255/decoding.rs @@ -2,6 +2,7 @@ use anyhow::anyhow; use curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar as IScalar}; +use minicbor::{Decode, Decoder, Encode, Encoder, encode::Write}; use super::{GroupElement, Scalar}; @@ -48,6 +49,46 @@ impl GroupElement { } } +impl Encode<()> for Scalar { + fn encode( + &self, + e: &mut Encoder, + ctx: &mut (), + ) -> Result<(), minicbor::encode::Error> { + self.to_bytes().encode(e, ctx) + } +} + +impl Decode<'_, ()> for Scalar { + fn decode( + d: &mut Decoder<'_>, + ctx: &mut (), + ) -> Result { + let bytes = <[u8; Scalar::BYTES_SIZE]>::decode(d, ctx)?; + Self::from_bytes(bytes).map_err(minicbor::decode::Error::message) + } +} + +impl Encode<()> for GroupElement { + fn encode( + &self, + e: &mut Encoder, + ctx: &mut (), + ) -> Result<(), minicbor::encode::Error> { + self.to_bytes().encode(e, ctx) + } +} + +impl Decode<'_, ()> for GroupElement { + fn decode( + d: &mut Decoder<'_>, + ctx: &mut (), + ) -> Result { + let compressed = <[u8; GroupElement::BYTES_SIZE]>::decode(d, ctx)?; + Self::from_bytes(&compressed).map_err(minicbor::decode::Error::message) + } +} + #[cfg(test)] mod tests { use test_strategy::proptest; @@ -67,4 +108,24 @@ mod tests { let ge2 = GroupElement::from_bytes(&bytes).unwrap(); assert_eq!(ge1, ge2); } + + #[proptest] + fn scalar_cbor_roundtrip(original: Scalar) { + let mut buffer = Vec::new(); + original + .encode(&mut Encoder::new(&mut buffer), &mut ()) + .unwrap(); + let decoded = Scalar::decode(&mut Decoder::new(&buffer), &mut ()).unwrap(); + assert_eq!(original, decoded); + } + + #[proptest] + fn group_element_cbor_roundtrip(original: GroupElement) { + let mut buffer = Vec::new(); + original + .encode(&mut Encoder::new(&mut buffer), &mut ()) + .unwrap(); + let decoded = GroupElement::decode(&mut Decoder::new(&buffer), &mut ()).unwrap(); + assert_eq!(original, decoded); + } } diff --git a/rust/catalyst-voting/src/crypto/group/ristretto255/mod.rs b/rust/catalyst-voting/src/crypto/group/ristretto255/mod.rs index 8011215088..e72f6602b9 100644 --- a/rust/catalyst-voting/src/crypto/group/ristretto255/mod.rs +++ b/rust/catalyst-voting/src/crypto/group/ristretto255/mod.rs @@ -22,11 +22,21 @@ use crate::crypto::{ }; /// Ristretto group scalar. -#[derive(Debug, Clone, PartialEq, Eq)] +/// +/// The CBOR CDDL schema: +/// ```cddl +/// zkproof-ed25519-scalar = bytes .size 32 +/// ``` +#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[must_use] pub struct Scalar(IScalar); /// Ristretto group element. +/// +/// The CBOR CDDL schema: +/// ```cddl +/// elgamal-ristretto255-group-element = bytes .size 32 +/// ``` #[derive(Debug, Clone, PartialEq, Eq)] #[must_use] pub struct GroupElement(RistrettoPoint); diff --git a/rust/catalyst-voting/src/crypto/zk_unit_vector/decoding.rs b/rust/catalyst-voting/src/crypto/zk_unit_vector/decoding.rs index 7fe241eb63..98ac45fb28 100644 --- a/rust/catalyst-voting/src/crypto/zk_unit_vector/decoding.rs +++ b/rust/catalyst-voting/src/crypto/zk_unit_vector/decoding.rs @@ -1,188 +1,209 @@ //! ZK Unit Vector objects decoding implementation -use std::io::Read; - -use anyhow::anyhow; - -use super::{Announcement, Ciphertext, GroupElement, ResponseRandomness, Scalar, UnitVectorProof}; -use crate::utils::read_array; - -impl UnitVectorProof { - /// Get an underlying vector length. - /// - /// **Note** each vector field has the same length. - #[must_use] - pub fn size(&self) -> usize { - self.0.len() - } - - /// Decode `UnitVectorProof` from bytes. - /// - /// # Errors - /// - Cannot decode announcement value. - /// - Cannot decode ciphertext value. - /// - Cannot decode response randomness value. - /// - Cannot decode scalar value. - pub fn from_bytes( - reader: &mut R, - len: usize, - ) -> anyhow::Result { - let ann = (0..len) - .map(|i| { - let bytes = read_array(reader)?; - Announcement::from_bytes(&bytes).map_err(|e| { - anyhow!( - "Cannot decode announcement at {i}, \ - error: {e}." - ) - }) - }) - .collect::>()?; - let dl = (0..len) - .map(|i| { - let bytes = read_array(reader)?; - Ciphertext::from_bytes(&bytes).map_err(|e| { - anyhow!( - "Cannot decode ciphertext at {i}, \ - error: {e}." - ) - }) - }) - .collect::>()?; - let rr = (0..len) - .map(|i| { - let bytes = read_array(reader)?; - ResponseRandomness::from_bytes(&bytes).map_err(|e| { - anyhow!( - "Cannot decode response randomness at {i}, \ - error: {e}." - ) - }) - }) - .collect::>()?; - - let bytes = read_array(reader)?; - let scalar = - Scalar::from_bytes(bytes).map_err(|_| anyhow!("Cannot decode scalar field."))?; - Ok(Self(ann, dl, rr, scalar)) - } - - /// Get a deserialized bytes size - #[must_use] - fn bytes_size(&self) -> usize { - Scalar::BYTES_SIZE - + self.0.len() * Announcement::BYTES_SIZE - + self.0.len() * Ciphertext::BYTES_SIZE - + self.0.len() * ResponseRandomness::BYTES_SIZE - } - - /// Encode `EncryptedVote` tos bytes. - #[must_use] - pub fn to_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(self.bytes_size()); - self.0 - .iter() - .for_each(|c| res.extend_from_slice(&c.to_bytes())); - self.1 - .iter() - .for_each(|c| res.extend_from_slice(&c.to_bytes())); - self.2 - .iter() - .for_each(|c| res.extend_from_slice(&c.to_bytes())); - res.extend_from_slice(&self.3.to_bytes()); - res +use cbork_utils::decode_helper::decode_array_len; +use minicbor::{Decode, Decoder, Encode, Encoder, encode::Write}; + +use super::{ResponseRandomness, UnitVectorProof}; +use crate::crypto::{ + elgamal::Ciphertext, + group::{GroupElement, Scalar}, + zk_unit_vector::randomness_announcements::Announcement, +}; + +/// A number of elements in the +/// `zkproof-elgamal-ristretto255-unit-vector-with-single-selection-item` data type. +/// +/// The CBOR CDDL schema: +/// ```cddl +/// zkproof-elgamal-ristretto255-unit-vector-with-single-selection-item = ( zkproof-elgamal-announcement, ~elgamal-ristretto255-encrypted-choice, zkproof-ed25519-r-response ) +/// +/// zkproof-elgamal-announcement = ( zkproof-elgamal-group-element, zkproof-elgamal-group-element, zkproof-elgamal-group-element ) +/// +/// zkproof-elgamal-group-element = bytes .size 32 +/// +/// elgamal-ristretto255-encrypted-choice = [ +/// c1: elgamal-ristretto255-group-element +/// c2: elgamal-ristretto255-group-element +/// ] +/// +/// zkproof-ed25519-r-response = ( zkproof-ed25519-scalar, zkproof-ed25519-scalar, zkproof-ed25519-scalar ) +/// +/// zkproof-ed25519-scalar = bytes .size 32 +/// ``` +/// +/// Therefore, the total number consists of the following: +/// - 8 (zkproof-elgamal-ristretto255-unit-vector-with-single-selection-item) +/// - 3 (zkproof-elgamal-announcement = x3 zkproof-elgamal-group-element) +/// - 2 (elgamal-ristretto255-encrypted-choice = x2 +/// elgamal-ristretto255-group-element) +/// - 3 (zkproof-ed25519-r-response = x3 zkproof-ed25519-scalar) +const ITEM_ELEMENTS_LEN: u64 = 8; + +/// A minimal length of the underlying CBOR array of the `UnitVectorProof` data type. +/// +/// The CBOR CDDL schema: +/// ```cddl +/// zkproof-elgamal-ristretto255-unit-vector-with-single-selection = [ +zkproof-elgamal-ristretto255-unit-vector-with-single-selection-item, zkproof-ed25519-scalar ] +/// ``` +const MIN_PROOF_CBOR_ARRAY_LEN: u64 = ITEM_ELEMENTS_LEN + 1; + +impl Encode<()> for Announcement { + fn encode( + &self, + e: &mut Encoder, + ctx: &mut (), + ) -> Result<(), minicbor::encode::Error> { + self.i.encode(e, ctx)?; + self.b.encode(e, ctx)?; + self.a.encode(e, ctx) } } -impl Announcement { - /// `Announcement` bytes size - pub const BYTES_SIZE: usize = GroupElement::BYTES_SIZE * 3; - - /// Decode `Announcement` from bytes. - /// - /// # Errors - /// - `AnnouncementDecodingError` - #[allow(clippy::unwrap_used)] - pub fn from_bytes(bytes: &[u8; Self::BYTES_SIZE]) -> anyhow::Result { - let i = GroupElement::from_bytes(bytes[0..32].try_into().unwrap()) - .map_err(|_| anyhow!("Cannot decode `i` group element field."))?; - let b = GroupElement::from_bytes(bytes[32..64].try_into().unwrap()) - .map_err(|_| anyhow!("Cannot decode `b` group element field."))?; - let a = GroupElement::from_bytes(bytes[64..96].try_into().unwrap()) - .map_err(|_| anyhow!("Cannot decode `a` group element field."))?; +impl Decode<'_, ()> for Announcement { + fn decode( + d: &mut Decoder<'_>, + ctx: &mut (), + ) -> Result { + let i = GroupElement::decode(d, ctx)?; + let b = GroupElement::decode(d, ctx)?; + let a = GroupElement::decode(d, ctx)?; Ok(Self { i, b, a }) } +} - /// Encode `Announcement` tos bytes. - #[must_use] - pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] { - let mut res = [0; 96]; - res[0..32].copy_from_slice(&self.i.to_bytes()); - res[32..64].copy_from_slice(&self.b.to_bytes()); - res[64..96].copy_from_slice(&self.a.to_bytes()); - res +impl Encode<()> for ResponseRandomness { + fn encode( + &self, + e: &mut Encoder, + ctx: &mut (), + ) -> Result<(), minicbor::encode::Error> { + self.z.encode(e, ctx)?; + self.w.encode(e, ctx)?; + self.v.encode(e, ctx) } } -impl ResponseRandomness { - /// `ResponseRandomness` bytes size - pub const BYTES_SIZE: usize = Scalar::BYTES_SIZE * 3; - - /// Decode `ResponseRandomness` from bytes. - /// - /// # Errors - /// - Cannot decode scalar field. - #[allow(clippy::unwrap_used)] - pub fn from_bytes(bytes: &[u8; Self::BYTES_SIZE]) -> anyhow::Result { - let z = Scalar::from_bytes(bytes[0..32].try_into().unwrap()) - .map_err(|_| anyhow!("Cannot decode `z` scalar field."))?; - let w = Scalar::from_bytes(bytes[32..64].try_into().unwrap()) - .map_err(|_| anyhow!("Cannot decode `w` scalar field."))?; - let v = Scalar::from_bytes(bytes[64..96].try_into().unwrap()) - .map_err(|_| anyhow!("Cannot decode `v` scalar field."))?; +impl Decode<'_, ()> for ResponseRandomness { + fn decode( + d: &mut Decoder<'_>, + ctx: &mut (), + ) -> Result { + let z = Scalar::decode(d, ctx)?; + let w = Scalar::decode(d, ctx)?; + let v = Scalar::decode(d, ctx)?; Ok(Self { z, w, v }) } +} + +impl Encode<()> for UnitVectorProof { + fn encode( + &self, + e: &mut Encoder, + ctx: &mut (), + ) -> Result<(), minicbor::encode::Error> { + if self.0.len() != self.1.len() || self.0.len() != self.2.len() { + return Err(minicbor::encode::Error::message(format!( + "All UnitVectorProof parts must have the same length: announcements = {}, choice = {}, responses = {}", + self.0.len(), + self.1.len(), + self.2.len() + ))); + } + + e.array(2)?; + 0.encode(e, ctx)?; + + e.array(self.0.len() as u64 * ITEM_ELEMENTS_LEN + 1)?; + for ((announcement, choice), response) in + self.0.iter().zip(self.1.iter()).zip(self.2.iter()) + { + announcement.encode(e, ctx)?; + choice.first().encode(e, ctx)?; + choice.second().encode(e, ctx)?; + response.encode(e, ctx)?; + } + self.3.encode(e, ctx) + } +} - /// Encode `ResponseRandomness` tos bytes. - #[must_use] - pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] { - let mut res = [0; 96]; - res[0..32].copy_from_slice(&self.z.to_bytes()); - res[32..64].copy_from_slice(&self.w.to_bytes()); - res[64..96].copy_from_slice(&self.v.to_bytes()); - res +impl Decode<'_, ()> for UnitVectorProof { + fn decode( + d: &mut Decoder<'_>, + ctx: &mut (), + ) -> Result { + let len = decode_array_len(d, "UnitVectorProof")?; + if len != 2 { + return Err(minicbor::decode::Error::message(format!( + "Unexpected UnitVectorProof array length {len}, expected 2" + ))); + } + + let version = u64::decode(d, ctx)?; + if version != 0 { + return Err(minicbor::decode::Error::message(format!( + "Unexpected UnitVectorProof version value: {version}, expected 0" + ))); + } + + let len = decode_array_len(d, "UnitVectorProof inner array")?; + if len < MIN_PROOF_CBOR_ARRAY_LEN || !len.is_multiple_of(MIN_PROOF_CBOR_ARRAY_LEN) { + return Err(minicbor::decode::Error::message(format!( + "Unexpected rUnitVectorProof inner array length {len}, expected multiplier of {MIN_PROOF_CBOR_ARRAY_LEN}" + ))); + } + + let elements = len / MIN_PROOF_CBOR_ARRAY_LEN; + let mut announcements = Vec::with_capacity(elements as usize); + let mut choices = Vec::with_capacity(elements as usize); + let mut responses = Vec::with_capacity(elements as usize); + + for _ in 0..elements { + announcements.push(Announcement::decode(d, ctx)?); + let first = GroupElement::decode(d, ctx)?; + let second = GroupElement::decode(d, ctx)?; + choices.push(Ciphertext::from_elements(first, second)); + responses.push(ResponseRandomness::decode(d, ctx)?); + } + let scalar = Scalar::decode(d, ctx)?; + + Ok(Self(announcements, choices, responses, scalar)) } } #[cfg(test)] #[allow(clippy::explicit_deref_methods)] mod tests { - use test_strategy::proptest; + use proptest::property_test; use super::*; - #[proptest] - fn proof_to_bytes_from_bytes_test( - #[strategy(0..5usize)] _size: usize, - #[any(#_size)] p1: UnitVectorProof, - ) { - let bytes = p1.to_bytes(); - assert_eq!(bytes.len(), p1.bytes_size()); - let p2 = UnitVectorProof::from_bytes(&mut bytes.as_slice(), p1.size()).unwrap(); - assert_eq!(p1, p2); + #[property_test] + fn response_randomness_cbor_roundtrip(original: ResponseRandomness) { + let mut buffer = Vec::new(); + original + .encode(&mut Encoder::new(&mut buffer), &mut ()) + .unwrap(); + let decoded = ResponseRandomness::decode(&mut Decoder::new(&buffer), &mut ()).unwrap(); + assert_eq!(original, decoded); } - #[proptest] - fn announcement_to_bytes_from_bytes_test(a1: Announcement) { - let bytes = a1.to_bytes(); - let a2 = Announcement::from_bytes(&bytes).unwrap(); - assert_eq!(a1, a2); + #[property_test] + fn announcement_cbor_roundtrip(original: Announcement) { + let mut buffer = Vec::new(); + original + .encode(&mut Encoder::new(&mut buffer), &mut ()) + .unwrap(); + let decoded = Announcement::decode(&mut Decoder::new(&buffer), &mut ()).unwrap(); + assert_eq!(original, decoded); } - #[proptest] - fn response_randomness_to_bytes_from_bytes_test(r1: ResponseRandomness) { - let bytes = r1.to_bytes(); - let r2 = ResponseRandomness::from_bytes(&bytes).unwrap(); - assert_eq!(r1, r2); + #[property_test] + fn unit_vector_proof_cbor_roundtrip(original: UnitVectorProof) { + let mut buffer = Vec::new(); + original + .encode(&mut Encoder::new(&mut buffer), &mut ()) + .unwrap(); + let decoded = UnitVectorProof::decode(&mut Decoder::new(&buffer), &mut ()).unwrap(); + assert_eq!(original, decoded); } } diff --git a/rust/catalyst-voting/src/crypto/zk_unit_vector/mod.rs b/rust/catalyst-voting/src/crypto/zk_unit_vector/mod.rs index 0d693b449d..56488ba9bc 100644 --- a/rust/catalyst-voting/src/crypto/zk_unit_vector/mod.rs +++ b/rust/catalyst-voting/src/crypto/zk_unit_vector/mod.rs @@ -27,7 +27,16 @@ use crate::crypto::{ }; /// Unit vector proof struct -#[derive(Debug, Clone, PartialEq, Eq)] +/// +/// The CBOR CDDL schema: +/// ```cddl +/// row-proof = [0, zkproof-elgamal-ristretto255-unit-vector-with-single-selection ] +/// +/// zkproof-elgamal-ristretto255-unit-vector-with-single-selection = [ +zkproof-elgamal-ristretto255-unit-vector-with-single-selection-item, zkproof-ed25519-scalar ] +/// +/// zkproof-elgamal-ristretto255-unit-vector-with-single-selection-item = ( zkproof-elgamal-announcement, ~elgamal-ristretto255-encrypted-choice, zkproof-ed25519-r-response ) +/// ``` +#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[must_use] pub struct UnitVectorProof( Vec, @@ -273,7 +282,7 @@ mod arbitrary_impl { any_with::<( Vec<((Announcement, Ciphertext), ResponseRandomness)>, Scalar, - )>(((size_range(size), (((), ()), ())), ())) + )>(((size_range(size + 1), (((), ()), ())), ())) .prop_map(|(val, scalar)| { let (vec, rr): (Vec<_>, Vec<_>) = val.into_iter().unzip(); let (an, cipher) = vec.into_iter().unzip(); diff --git a/rust/catalyst-voting/src/crypto/zk_unit_vector/randomness_announcements.rs b/rust/catalyst-voting/src/crypto/zk_unit_vector/randomness_announcements.rs index 13ec823c75..6e8be5cb38 100644 --- a/rust/catalyst-voting/src/crypto/zk_unit_vector/randomness_announcements.rs +++ b/rust/catalyst-voting/src/crypto/zk_unit_vector/randomness_announcements.rs @@ -31,7 +31,12 @@ impl BlindingRandomness { /// First announcement, formed by I, B, A group elements. These group elements /// are the commitments of the binary representation of the unit vector index. -#[derive(Clone, Debug, Eq, PartialEq)] +/// +/// The CBOR CDDL schema: +/// ```cddl +/// zkproof-elgamal-announcement = ( zkproof-elgamal-group-element, zkproof-elgamal-group-element, zkproof-elgamal-group-element ) +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct Announcement { pub(crate) i: GroupElement, pub(crate) b: GroupElement, @@ -61,7 +66,12 @@ impl Announcement { /// Response encoding the bits of the private vector, and the randomness of /// `BlindingRandomness`. -#[derive(Clone, Debug, Eq, PartialEq)] +/// +/// The CBOR CDDL schema: +/// ```cddl +/// zkproof-ed25519-r-response = ( zkproof-ed25519-scalar, zkproof-ed25519-scalar, zkproof-ed25519-scalar ) +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct ResponseRandomness { pub(crate) z: Scalar, pub(crate) w: Scalar, diff --git a/rust/catalyst-voting/src/vote_protocol/voter/decoding.rs b/rust/catalyst-voting/src/vote_protocol/voter/decoding.rs index 75c7a15d5b..4071fb726f 100644 --- a/rust/catalyst-voting/src/vote_protocol/voter/decoding.rs +++ b/rust/catalyst-voting/src/vote_protocol/voter/decoding.rs @@ -4,11 +4,8 @@ use std::io::Read; use anyhow::anyhow; -use super::{EncryptedVote, proof::VoterProof}; -use crate::{ - crypto::{elgamal::Ciphertext, zk_unit_vector::UnitVectorProof}, - utils::read_array, -}; +use super::EncryptedVote; +use crate::{crypto::elgamal::Ciphertext, utils::read_array}; impl EncryptedVote { /// Get an underlying vector length. @@ -53,36 +50,6 @@ impl EncryptedVote { } } -impl VoterProof { - /// Get an underlying vector length. - /// - /// **Note** each vector field has the same length. - #[must_use] - pub fn size(&self) -> usize { - self.0.size() - } - - /// Decode `VoterProof` from bytes. - /// - /// # Errors - /// - Cannot decode announcement value. - /// - Cannot decode ciphertext value. - /// - Cannot decode response randomness value. - /// - Cannot decode scalar value. - pub fn from_bytes( - reader: &mut R, - len: usize, - ) -> anyhow::Result { - UnitVectorProof::from_bytes(reader, len).map(Self) - } - - /// Encode `EncryptedVote` tos bytes. - #[must_use] - pub fn to_bytes(&self) -> Vec { - self.0.to_bytes() - } -} - #[cfg(test)] #[allow(clippy::explicit_deref_methods)] mod tests {