From e57fe646791761f360e373530603623d57a9cb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Zwoli=C5=84ski?= Date: Fri, 1 Mar 2024 10:44:26 +0100 Subject: [PATCH] fix: row verification logic (#235) --- types/src/row.rs | 95 +++++++++---------------- types/test_data/shwap_samples/row.data | Bin 4132 -> 0 bytes 2 files changed, 35 insertions(+), 60 deletions(-) delete mode 100644 types/test_data/shwap_samples/row.data diff --git a/types/src/row.rs b/types/src/row.rs index 9ef91d3c..f365f22e 100644 --- a/types/src/row.rs +++ b/types/src/row.rs @@ -17,9 +17,10 @@ use multihash::Multihash; use nmt_rs::NamespaceMerkleHasher; use serde::{Deserialize, Serialize}; +use crate::consts::appconsts::SHARE_SIZE; use crate::nmt::NS_SIZE; use crate::nmt::{Namespace, NamespacedSha2Hasher, Nmt}; -use crate::rsmt2d::ExtendedDataSquare; +use crate::rsmt2d::{is_ods_square, ExtendedDataSquare}; use crate::{DataAvailabilityHeader, Error, Result}; /// The size of the [`RowId`] hash in `multihash`. @@ -62,22 +63,20 @@ impl Row { /// verify the row against roots from DAH pub fn verify(&self, dah: &DataAvailabilityHeader) -> Result<()> { let square_len = self.shares.len(); - - let (data_shares, parity_shares) = self.shares.split_at(square_len / 2); + let row = self.row_id.index as usize; let mut tree = Nmt::with_hasher(NamespacedSha2Hasher::with_ignore_max_ns(true)); - for s in data_shares { - let ns = Namespace::from_raw(&s[..NS_SIZE])?; + for (col, s) in self.shares.iter().enumerate() { + let ns = if is_ods_square(row, col, square_len) { + Namespace::from_raw(&s[..NS_SIZE])? + } else { + Namespace::PARITY_SHARE + }; tree.push_leaf(s, *ns).map_err(Error::Nmt)?; } - for s in parity_shares { - tree.push_leaf(s, *Namespace::PARITY_SHARE) - .map_err(Error::Nmt)?; - } - let index = self.row_id.index.into(); - let Some(root) = dah.row_root(index) else { - return Err(Error::EdsIndexOutOfRange(index)); + let Some(root) = dah.row_root(row) else { + return Err(Error::EdsIndexOutOfRange(row)); }; if tree.root().hash() != root.hash() { @@ -95,16 +94,14 @@ impl TryFrom for Row { fn try_from(row: RawRow) -> Result { let row_id = RowId::decode(&row.row_id)?; - let shares = row.row_half; + let mut shares = row.row_half; + let data_shares = shares.len(); - // TODO: only original data shares are sent over the wire, we need leopard codec to - // re-compute parity shares - // - // somehow_generate_parity_shares(&mut shares); + shares.resize(shares.len() * 2, vec![0; SHARE_SIZE]); - let _ = Row { row_id, shares }; + leopard_codec::encode(&mut shares, data_shares)?; - unimplemented!() + Ok(Row { row_id, shares }) } } @@ -215,6 +212,7 @@ impl From for CidGeneric { mod tests { use super::*; use crate::consts::appconsts::SHARE_SIZE; + use crate::test_utils::generate_eds; #[test] fn round_trip_test() { @@ -317,49 +315,26 @@ mod tests { assert_eq!(row_err, CidError::InvalidCidCodec(1234)); } - #[test] - // TODO: - // fully testing protobuf deserialisation requires leopard codec, to generate parity shares. - // By asserting that we've reached `unimplemented!`, we rely on implementation detail to - // check whether protobuf, RowId and Share deserialisations were successful (but can't check - // the actual data) - // Once we have leopard codec, remove `should_panic` to enable full test functionality - #[should_panic(expected = "not implemented")] - fn decode_row_bytes() { - let bytes = include_bytes!("../test_data/shwap_samples/row.data"); - let mut row = Row::decode(&bytes[..]).unwrap(); - - row.row_id.index = 64; - row.row_id.block_height = 255; - - assert_eq!(row.row_id.index, 64); - assert_eq!(row.row_id.block_height, 255); - - for (idx, share) in row.shares.iter().enumerate() { - let expected_ns = Namespace::new_v0(&[idx as u8]).unwrap(); - let ns = Namespace::from_raw(&share[..NS_SIZE]).unwrap(); - assert_eq!(ns, expected_ns); - let data = [0; SHARE_SIZE - NS_SIZE]; - assert_eq!(share[NS_SIZE..], data); - } - } - #[test] fn test_validate() { - let eds_json = include_str!("../test_data/shwap_samples/eds.json"); - let eds: ExtendedDataSquare = serde_json::from_str(eds_json).unwrap(); - let dah_json = include_str!("../test_data/shwap_samples/dah.json"); - let dah: DataAvailabilityHeader = serde_json::from_str(dah_json).unwrap(); - - let index = 1; - let row = Row { - row_id: RowId { - block_height: 1, - index, - }, - shares: eds.row(index.into()).unwrap(), - }; + for _ in 0..10 { + let eds = generate_eds(2 << (rand::random::() % 8)); + let dah = DataAvailabilityHeader::from_eds(&eds); + + let index = rand::random::() % eds.square_len() as u16; - row.verify(&dah).unwrap(); + let row = Row { + row_id: RowId { + block_height: 1, + index, + }, + shares: eds.row(index.into()).unwrap(), + }; + + let encoded = row.encode_vec().unwrap(); + let decoded = Row::decode(encoded.as_ref()).unwrap(); + + decoded.verify(&dah).unwrap(); + } } } diff --git a/types/test_data/shwap_samples/row.data b/types/test_data/shwap_samples/row.data deleted file mode 100644 index 57c0d37818a5ce663adac204b5ca02fcb5f94c34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4132 zcmeH}D-Hl448{19OmZTQ#?3*1e|}|VnQT)rvv6mJIaYbcUr+-gfe6(?!WIc6k_#xS lNFYPCkg!Dp|55NCgGiwIH-IM;2{gPQ{{ln;-M;}m;Q@GW1|R?c