From fd0e06217846d445171bcaa34359ea51b1957ef7 Mon Sep 17 00:00:00 2001 From: jbcaron Date: Fri, 21 Jun 2024 11:01:28 +0400 Subject: [PATCH 1/6] add visit_seq on Felt --- crates/starknet-types-core/src/felt/mod.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/starknet-types-core/src/felt/mod.rs b/crates/starknet-types-core/src/felt/mod.rs index e3a7a19..dc52b52 100644 --- a/crates/starknet-types-core/src/felt/mod.rs +++ b/crates/starknet-types-core/src/felt/mod.rs @@ -935,7 +935,11 @@ mod serde_impl { where D: ::serde::Deserializer<'de>, { - deserializer.deserialize_str(FeltVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_str(FeltVisitor) + } else { + deserializer.deserialize_seq(FeltVisitor) + } } } @@ -960,6 +964,19 @@ mod serde_impl { .ok_or(String::from("Expected hex string to be prefixed by '0x'")) .map_err(de::Error::custom) } + + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let mut bytes = [0u8; 32]; + for (i, byte) in bytes.iter_mut().enumerate() { + *byte = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + Ok(Felt::from_bytes_be_slice(&bytes)) + } } } From d74fc67b658275633f5ddc0e2f58d6d30a37649d Mon Sep 17 00:00:00 2001 From: jbcaron Date: Fri, 21 Jun 2024 15:35:43 +0400 Subject: [PATCH 2/6] add tests deserialize Felt --- crates/starknet-types-core/src/felt/mod.rs | 165 ++++++++++++++++++++- 1 file changed, 161 insertions(+), 4 deletions(-) diff --git a/crates/starknet-types-core/src/felt/mod.rs b/crates/starknet-types-core/src/felt/mod.rs index f0c27f7..11300eb 100644 --- a/crates/starknet-types-core/src/felt/mod.rs +++ b/crates/starknet-types-core/src/felt/mod.rs @@ -1639,15 +1639,172 @@ mod test { #[test] #[cfg(feature = "serde")] fn deserialize() { - assert_de_tokens(&Felt::ZERO, &[Token::String("0x0")]); - assert_de_tokens(&Felt::TWO, &[Token::String("0x2")]); - assert_de_tokens(&Felt::THREE, &[Token::String("0x3")]); + assert_de_tokens(&Felt::ZERO.readable(), &[Token::String("0x0")]); + assert_de_tokens(&Felt::TWO.readable(), &[Token::String("0x2")]); + assert_de_tokens(&Felt::THREE.readable(), &[Token::String("0x3")]); assert_de_tokens( - &Felt::MAX, + &Felt::MAX.readable(), &[Token::String( "0x800000000000011000000000000000000000000000000000000000000000000", )], ); + + assert_de_tokens( + &Felt::ZERO.compact(), + &[ + Token::Seq { len: Some(32) }, + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::SeqEnd, + ], + ); + assert_de_tokens( + &Felt::TWO.compact(), + &[ + Token::Seq { len: Some(32) }, + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(2), + Token::SeqEnd, + ], + ); + assert_de_tokens( + &Felt::THREE.compact(), + &[ + Token::Seq { len: Some(32) }, + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(3), + Token::SeqEnd, + ], + ); + assert_de_tokens( + &Felt::MAX.compact(), + &[ + Token::Seq { len: Some(32) }, + Token::U8(8), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(17), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::SeqEnd, + ], + ); } #[test] From 6723646a79852a354526894d087fe0c3edee01bb Mon Sep 17 00:00:00 2001 From: jbcaron Date: Fri, 21 Jun 2024 19:15:04 +0400 Subject: [PATCH 3/6] Add detailed error handling for invalid sequence lengths during deserialization --- crates/starknet-types-core/src/felt/mod.rs | 93 +++++++++++++++++++++- 1 file changed, 90 insertions(+), 3 deletions(-) diff --git a/crates/starknet-types-core/src/felt/mod.rs b/crates/starknet-types-core/src/felt/mod.rs index 11300eb..57a876e 100644 --- a/crates/starknet-types-core/src/felt/mod.rs +++ b/crates/starknet-types-core/src/felt/mod.rs @@ -973,9 +973,16 @@ mod serde_impl { for (i, byte) in bytes.iter_mut().enumerate() { *byte = seq .next_element()? - .ok_or_else(|| de::Error::invalid_length(i, &"expected 32 bytes"))?; + .ok_or_else(|| de::Error::invalid_length(i, &"32 bytes"))?; } - Ok(Felt::from_bytes_be_slice(&bytes)) + if seq.next_element::()?.is_some() { + let mut count = 33; + while seq.next_element::()?.is_some() { + count += 1; + } + return Err(de::Error::invalid_length(count, &"32 bytes")); + } + Ok(Felt::from_bytes_be(&bytes)) } } } @@ -1105,7 +1112,9 @@ mod test { use proptest::prelude::*; use regex::Regex; #[cfg(feature = "serde")] - use serde_test::{assert_de_tokens, assert_ser_tokens, Configure, Token}; + use serde_test::{ + assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, Compact, Configure, Token, + }; #[test] fn test_debug_format() { @@ -1805,6 +1814,84 @@ mod test { Token::SeqEnd, ], ); + assert_de_tokens_error::>( + &[ + Token::Seq { len: Some(31) }, + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::SeqEnd, + ], + "invalid length 31, expected 32 bytes", + ); + assert_de_tokens_error::>( + &[ + Token::Seq { len: Some(33) }, + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::SeqEnd, + ], + "invalid length 33, expected 32 bytes", + ); } #[test] From d25da84cebe65f1be52370cd5d44343d53309395 Mon Sep 17 00:00:00 2001 From: jbcaron Date: Fri, 21 Jun 2024 21:26:04 +0400 Subject: [PATCH 4/6] use little-endian representaion --- crates/starknet-types-core/src/felt/mod.rs | 73 +++++++--------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/crates/starknet-types-core/src/felt/mod.rs b/crates/starknet-types-core/src/felt/mod.rs index 57a876e..d2db0d5 100644 --- a/crates/starknet-types-core/src/felt/mod.rs +++ b/crates/starknet-types-core/src/felt/mod.rs @@ -922,7 +922,7 @@ mod serde_impl { serializer.serialize_str(&format!("{:#x}", self)) } else { let mut seq = serializer.serialize_seq(Some(32))?; - for b in self.to_bytes_be() { + for b in self.to_bytes_le() { seq.serialize_element(&b)?; } seq.end() @@ -970,19 +970,21 @@ mod serde_impl { A: de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; - for (i, byte) in bytes.iter_mut().enumerate() { - *byte = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(i, &"32 bytes"))?; + for byte in bytes.iter_mut() { + if let Some(b) = seq.next_element()? { + *byte = b; + } else { + break; + } } if seq.next_element::()?.is_some() { let mut count = 33; while seq.next_element::()?.is_some() { count += 1; } - return Err(de::Error::invalid_length(count, &"32 bytes")); + return Err(de::Error::invalid_length(count, &"32 bytes max")); } - Ok(Felt::from_bytes_be(&bytes)) + Ok(Felt::from_bytes_le(&bytes)) } } } @@ -1701,6 +1703,7 @@ mod test { &Felt::TWO.compact(), &[ Token::Seq { len: Some(32) }, + Token::U8(2), Token::U8(0), Token::U8(0), Token::U8(0), @@ -1732,7 +1735,6 @@ mod test { Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(2), Token::SeqEnd, ], ); @@ -1740,6 +1742,7 @@ mod test { &Felt::THREE.compact(), &[ Token::Seq { len: Some(32) }, + Token::U8(3), Token::U8(0), Token::U8(0), Token::U8(0), @@ -1771,22 +1774,21 @@ mod test { Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(3), Token::SeqEnd, ], ); assert_de_tokens( - &Felt::MAX.compact(), + &Felt::ONE.compact(), &[ Token::Seq { len: Some(32) }, - Token::U8(8), + Token::U8(1), + Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(17), Token::U8(0), Token::U8(0), Token::U8(0), @@ -1814,43 +1816,14 @@ mod test { Token::SeqEnd, ], ); - assert_de_tokens_error::>( + assert_de_tokens( + &Felt::ONE.compact(), &[ - Token::Seq { len: Some(31) }, - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), + Token::Seq { len: Some(2) }, + Token::U8(1), Token::U8(0), Token::SeqEnd, ], - "invalid length 31, expected 32 bytes", ); assert_de_tokens_error::>( &[ @@ -1890,7 +1863,7 @@ mod test { Token::U8(0), Token::SeqEnd, ], - "invalid length 33, expected 32 bytes", + "invalid length 33, expected 32 bytes max", ); } @@ -1950,6 +1923,7 @@ mod test { &Felt::TWO.compact(), &[ Token::Seq { len: Some(32) }, + Token::U8(2), Token::U8(0), Token::U8(0), Token::U8(0), @@ -1981,7 +1955,6 @@ mod test { Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(2), Token::SeqEnd, ], ); @@ -1989,6 +1962,7 @@ mod test { &Felt::THREE.compact(), &[ Token::Seq { len: Some(32) }, + Token::U8(3), Token::U8(0), Token::U8(0), Token::U8(0), @@ -2020,7 +1994,6 @@ mod test { Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(3), Token::SeqEnd, ], ); @@ -2028,14 +2001,12 @@ mod test { &Felt::MAX.compact(), &[ Token::Seq { len: Some(32) }, - Token::U8(8), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(17), Token::U8(0), Token::U8(0), Token::U8(0), @@ -2054,12 +2025,14 @@ mod test { Token::U8(0), Token::U8(0), Token::U8(0), + Token::U8(17), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), + Token::U8(8), Token::SeqEnd, ], ); From 7b98204734d950b5eba009f4cbc660132eae9716 Mon Sep 17 00:00:00 2001 From: jbcaron Date: Wed, 26 Jun 2024 16:56:38 +0400 Subject: [PATCH 5/6] compress --- crates/starknet-types-core/src/felt/mod.rs | 362 ++++----------------- 1 file changed, 71 insertions(+), 291 deletions(-) diff --git a/crates/starknet-types-core/src/felt/mod.rs b/crates/starknet-types-core/src/felt/mod.rs index d2db0d5..a56fc32 100644 --- a/crates/starknet-types-core/src/felt/mod.rs +++ b/crates/starknet-types-core/src/felt/mod.rs @@ -913,6 +913,8 @@ mod serde_impl { use super::*; + const COMPRESSED: u8 = 0b1000_0000; + impl Serialize for Felt { fn serialize(&self, serializer: S) -> Result where @@ -921,11 +923,23 @@ mod serde_impl { if serializer.is_human_readable() { serializer.serialize_str(&format!("{:#x}", self)) } else { - let mut seq = serializer.serialize_seq(Some(32))?; - for b in self.to_bytes_le() { - seq.serialize_element(&b)?; + let bytes = self.to_bytes_be(); + let first_significant_byte = bytes.iter().position(|&b| b != 0).unwrap_or(31); + if first_significant_byte > 1 { + let len = 32 - first_significant_byte; + let mut seq = serializer.serialize_seq(Some(len + 1))?; + seq.serialize_element(&(len as u8 | COMPRESSED))?; + for b in &bytes[first_significant_byte..] { + seq.serialize_element(b)?; + } + seq.end() + } else { + let mut seq = serializer.serialize_seq(Some(32))?; + for b in &bytes { + seq.serialize_element(b)?; + } + seq.end() } - seq.end() } } } @@ -970,21 +984,29 @@ mod serde_impl { A: de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; - for byte in bytes.iter_mut() { - if let Some(b) = seq.next_element()? { - *byte = b; - } else { - break; + let first = seq + .next_element::()? + .ok_or(de::Error::invalid_length(0, &"more bytes"))?; + if first & COMPRESSED != 0 { + let len = first & !COMPRESSED; + for (i, byte) in bytes.iter_mut().skip(32 - len as usize).enumerate() { + if let Some(b) = seq.next_element()? { + *byte = b; + } else { + return Err(de::Error::invalid_length(i + 1, &"more bytes")); + } } - } - if seq.next_element::()?.is_some() { - let mut count = 33; - while seq.next_element::()?.is_some() { - count += 1; + } else { + bytes[0] = first; + for byte in bytes.iter_mut().skip(1) { + if let Some(b) = seq.next_element()? { + *byte = b; + } else { + return Err(de::Error::invalid_length(0, &"32 bytes")); + } } - return Err(de::Error::invalid_length(count, &"32 bytes max")); } - Ok(Felt::from_bytes_le(&bytes)) + Ok(Felt::from_bytes_be(&bytes)) } } } @@ -1663,207 +1685,46 @@ mod test { assert_de_tokens( &Felt::ZERO.compact(), &[ - Token::Seq { len: Some(32) }, - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::SeqEnd, - ], - ); - assert_de_tokens( - &Felt::TWO.compact(), - &[ - Token::Seq { len: Some(32) }, - Token::U8(2), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), + Token::Seq { len: Some(2) }, + Token::U8(1 | 0x80), Token::U8(0), Token::SeqEnd, ], ); assert_de_tokens( - &Felt::THREE.compact(), + &Felt::ONE.compact(), &[ - Token::Seq { len: Some(32) }, - Token::U8(3), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), + Token::Seq { len: Some(2) }, + Token::U8(1 | 0x80), + Token::U8(1), Token::SeqEnd, ], ); assert_de_tokens( - &Felt::ONE.compact(), + &Felt::TWO.compact(), &[ - Token::Seq { len: Some(32) }, - Token::U8(1), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), + Token::Seq { len: Some(2) }, + Token::U8(1 | 0x80), + Token::U8(2), Token::SeqEnd, ], ); assert_de_tokens( - &Felt::ONE.compact(), + &Felt::THREE.compact(), &[ Token::Seq { len: Some(2) }, - Token::U8(1), - Token::U8(0), + Token::U8(1 | 0x80), + Token::U8(3), Token::SeqEnd, ], ); assert_de_tokens_error::>( &[ - Token::Seq { len: Some(33) }, - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), + Token::Seq { len: Some(1) }, + Token::U8(1 | 0x80), Token::SeqEnd, ], - "invalid length 33, expected 32 bytes max", + "invalid length 1, expected more bytes", ); } @@ -1883,117 +1744,36 @@ mod test { assert_ser_tokens( &Felt::ZERO.compact(), &[ - Token::Seq { len: Some(32) }, - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), + Token::Seq { len: Some(2) }, + Token::U8(1 | 0x80), Token::U8(0), Token::SeqEnd, ], ); + assert_ser_tokens( + &Felt::ONE.compact(), + &[ + Token::Seq { len: Some(2) }, + Token::U8(1 | 0x80), + Token::U8(1), + Token::SeqEnd, + ], + ); assert_ser_tokens( &Felt::TWO.compact(), &[ - Token::Seq { len: Some(32) }, + Token::Seq { len: Some(2) }, + Token::U8(1 | 0x80), Token::U8(2), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), Token::SeqEnd, ], ); assert_ser_tokens( &Felt::THREE.compact(), &[ - Token::Seq { len: Some(32) }, + Token::Seq { len: Some(2) }, + Token::U8(1 | 0x80), Token::U8(3), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), - Token::U8(0), Token::SeqEnd, ], ); @@ -2001,12 +1781,14 @@ mod test { &Felt::MAX.compact(), &[ Token::Seq { len: Some(32) }, + Token::U8(8), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), + Token::U8(17), Token::U8(0), Token::U8(0), Token::U8(0), @@ -2025,14 +1807,12 @@ mod test { Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(17), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), Token::U8(0), - Token::U8(8), Token::SeqEnd, ], ); From fd2299f949526d8b4498d829168112544ecdc24f Mon Sep 17 00:00:00 2001 From: jbcaron Date: Thu, 27 Jun 2024 14:46:59 +0400 Subject: [PATCH 6/6] Implement compressed binary format for felts Co-authored-by: cchudant --- crates/starknet-types-core/src/felt/mod.rs | 199 +++++++++++++-------- 1 file changed, 127 insertions(+), 72 deletions(-) diff --git a/crates/starknet-types-core/src/felt/mod.rs b/crates/starknet-types-core/src/felt/mod.rs index a56fc32..0d6a9bc 100644 --- a/crates/starknet-types-core/src/felt/mod.rs +++ b/crates/starknet-types-core/src/felt/mod.rs @@ -909,7 +909,10 @@ mod arithmetic { mod serde_impl { use alloc::{format, string::String}; use core::fmt; - use serde::{de, ser::SerializeSeq, Deserialize, Serialize}; + use serde::{ + de, de::DeserializeSeed, ser::SerializeTuple, Deserialize, Deserializer, Serialize, + Serializer, + }; use super::*; @@ -925,20 +928,30 @@ mod serde_impl { } else { let bytes = self.to_bytes_be(); let first_significant_byte = bytes.iter().position(|&b| b != 0).unwrap_or(31); + + struct RestSerialize<'a>(&'a [u8]); + impl<'a> Serialize for RestSerialize<'a> { + fn serialize(&self, serializer: S) -> Result { + let mut tup = serializer.serialize_tuple(self.0.len())?; + for el in self.0 { + tup.serialize_element(el)?; + } + tup.end() + } + } + if first_significant_byte > 1 { let len = 32 - first_significant_byte; - let mut seq = serializer.serialize_seq(Some(len + 1))?; - seq.serialize_element(&(len as u8 | COMPRESSED))?; - for b in &bytes[first_significant_byte..] { - seq.serialize_element(b)?; - } - seq.end() + + let mut tup = serializer.serialize_tuple(2)?; + tup.serialize_element(&(len as u8 | COMPRESSED))?; + tup.serialize_element(&RestSerialize(&bytes[first_significant_byte..]))?; + tup.end() } else { - let mut seq = serializer.serialize_seq(Some(32))?; - for b in &bytes { - seq.serialize_element(b)?; - } - seq.end() + let mut tup = serializer.serialize_tuple(2)?; + tup.serialize_element(&bytes[0])?; + tup.serialize_element(&RestSerialize(&bytes[1..]))?; + tup.end() } } } @@ -952,7 +965,7 @@ mod serde_impl { if deserializer.is_human_readable() { deserializer.deserialize_str(FeltVisitor) } else { - deserializer.deserialize_seq(FeltVisitor) + deserializer.deserialize_tuple(2, FeltVisitor) } } } @@ -979,32 +992,47 @@ mod serde_impl { .map_err(de::Error::custom) } - fn visit_seq(self, mut seq: A) -> Result - where - A: de::SeqAccess<'de>, - { + fn visit_seq>(self, mut seq: A) -> Result { + struct RestDeserialize<'a>(&'a mut [u8]); + impl<'a, 'de> DeserializeSeed<'de> for RestDeserialize<'a> { + type Value = (); + fn deserialize>( + self, + deserializer: D, + ) -> Result { + struct RestDeserializeVisitor<'a>(&'a mut [u8]); + impl<'a, 'de> de::Visitor<'de> for RestDeserializeVisitor<'a> { + type Value = (); + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("Failed to deserialize felt") + } + fn visit_seq>( + self, + mut seq: A, + ) -> Result { + for (i, el) in self.0.iter_mut().enumerate() { + *el = seq + .next_element::()? + .ok_or(de::Error::invalid_length(i + 1, &"more bytes"))?; + } + Ok(()) + } + } + deserializer.deserialize_tuple(self.0.len(), RestDeserializeVisitor(self.0)) + } + } + let mut bytes = [0u8; 32]; let first = seq .next_element::()? - .ok_or(de::Error::invalid_length(0, &"more bytes"))?; + .ok_or(de::Error::invalid_length(1, &"tagging byte"))?; + if first & COMPRESSED != 0 { let len = first & !COMPRESSED; - for (i, byte) in bytes.iter_mut().skip(32 - len as usize).enumerate() { - if let Some(b) = seq.next_element()? { - *byte = b; - } else { - return Err(de::Error::invalid_length(i + 1, &"more bytes")); - } - } + seq.next_element_seed(RestDeserialize(&mut bytes[32 - len as usize..]))?; } else { bytes[0] = first; - for byte in bytes.iter_mut().skip(1) { - if let Some(b) = seq.next_element()? { - *byte = b; - } else { - return Err(de::Error::invalid_length(0, &"32 bytes")); - } - } + seq.next_element_seed(RestDeserialize(&mut bytes[1..]))?; } Ok(Felt::from_bytes_be(&bytes)) } @@ -1136,9 +1164,7 @@ mod test { use proptest::prelude::*; use regex::Regex; #[cfg(feature = "serde")] - use serde_test::{ - assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, Compact, Configure, Token, - }; + use serde_test::{assert_de_tokens, assert_ser_tokens, Configure, Token}; #[test] fn test_debug_format() { @@ -1685,46 +1711,76 @@ mod test { assert_de_tokens( &Felt::ZERO.compact(), &[ - Token::Seq { len: Some(2) }, + Token::Tuple { len: 2 }, Token::U8(1 | 0x80), + Token::Tuple { len: 1 }, Token::U8(0), - Token::SeqEnd, - ], - ); - assert_de_tokens( - &Felt::ONE.compact(), - &[ - Token::Seq { len: Some(2) }, - Token::U8(1 | 0x80), - Token::U8(1), - Token::SeqEnd, + Token::TupleEnd, + Token::TupleEnd, ], ); assert_de_tokens( &Felt::TWO.compact(), &[ - Token::Seq { len: Some(2) }, + Token::Tuple { len: 2 }, Token::U8(1 | 0x80), + Token::Tuple { len: 1 }, Token::U8(2), - Token::SeqEnd, + Token::TupleEnd, + Token::TupleEnd, ], ); assert_de_tokens( &Felt::THREE.compact(), &[ - Token::Seq { len: Some(2) }, + Token::Tuple { len: 2 }, Token::U8(1 | 0x80), + Token::Tuple { len: 1 }, Token::U8(3), - Token::SeqEnd, + Token::TupleEnd, + Token::TupleEnd, ], ); - assert_de_tokens_error::>( + assert_de_tokens( + &Felt::MAX.compact(), &[ - Token::Seq { len: Some(1) }, - Token::U8(1 | 0x80), - Token::SeqEnd, + Token::Tuple { len: 2 }, + Token::U8(8), + Token::Tuple { len: 31 }, + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(17), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::U8(0), + Token::TupleEnd, + Token::TupleEnd, ], - "invalid length 1, expected more bytes", ); } @@ -1744,44 +1800,42 @@ mod test { assert_ser_tokens( &Felt::ZERO.compact(), &[ - Token::Seq { len: Some(2) }, + Token::Tuple { len: 2 }, Token::U8(1 | 0x80), + Token::Tuple { len: 1 }, Token::U8(0), - Token::SeqEnd, - ], - ); - assert_ser_tokens( - &Felt::ONE.compact(), - &[ - Token::Seq { len: Some(2) }, - Token::U8(1 | 0x80), - Token::U8(1), - Token::SeqEnd, + Token::TupleEnd, + Token::TupleEnd, ], ); assert_ser_tokens( &Felt::TWO.compact(), &[ - Token::Seq { len: Some(2) }, + Token::Tuple { len: 2 }, Token::U8(1 | 0x80), + Token::Tuple { len: 1 }, Token::U8(2), - Token::SeqEnd, + Token::TupleEnd, + Token::TupleEnd, ], ); assert_ser_tokens( &Felt::THREE.compact(), &[ - Token::Seq { len: Some(2) }, + Token::Tuple { len: 2 }, Token::U8(1 | 0x80), + Token::Tuple { len: 1 }, Token::U8(3), - Token::SeqEnd, + Token::TupleEnd, + Token::TupleEnd, ], ); assert_ser_tokens( &Felt::MAX.compact(), &[ - Token::Seq { len: Some(32) }, + Token::Tuple { len: 2 }, Token::U8(8), + Token::Tuple { len: 31 }, Token::U8(0), Token::U8(0), Token::U8(0), @@ -1813,7 +1867,8 @@ mod test { Token::U8(0), Token::U8(0), Token::U8(0), - Token::SeqEnd, + Token::TupleEnd, + Token::TupleEnd, ], ); }