Skip to content

Instantly share code, notes, and snippets.

@cchudant
Created June 26, 2024 19:00
Show Gist options
  • Save cchudant/9bbb025c60a9fe23ca56b895fdcff13c to your computer and use it in GitHub Desktop.
Save cchudant/9bbb025c60a9fe23ca56b895fdcff13c to your computer and use it in GitHub Desktop.
use core::fmt;
use serde::de::DeserializeSeed;
use serde::ser::SerializeTuple;
use serde::Deserializer;
use serde::Serializer;
use serde::{de, Deserialize, Serialize};
const COMPRESSED: u8 = 0b1000_0000;
#[derive(PartialEq, Debug, Copy, Clone)]
struct Felt([u8; 32]);
impl Serialize for Felt {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
todo!()
//serializer.serialize_str(&format!("{:#x}", self))
} else {
let bytes = self.0;
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<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
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 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 tup = serializer.serialize_tuple(2)?;
tup.serialize_element(&bytes[0])?;
tup.serialize_element(&RestSerialize(&bytes[1..]))?;
tup.end()
}
}
}
}
impl<'de> Deserialize<'de> for Felt {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct FeltVisitor;
impl<'de> de::Visitor<'de> for FeltVisitor {
type Value = Felt;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("Failed to deserialize felt")
}
fn visit_str<E: de::Error>(self, _value: &str) -> Result<Self::Value, E> {
// Strip the '0x' prefix from the encoded hex string
// value
// .strip_prefix("0x")
// .and_then(|v| FieldElement::<Stark252PrimeField>::from_hex(v).ok())
// .map(Felt)
// .ok_or(String::from("Expected hex string to be prefixed by '0x'"))
// .map_err(de::Error::custom)
todo!()
}
fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
struct RestDeserialize<'a>(&'a mut [u8]);
impl<'a, 'de> DeserializeSeed<'de> for RestDeserialize<'a> {
type Value = ();
fn deserialize<D: Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
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<A: de::SeqAccess<'de>>(
self,
mut seq: A,
) -> Result<Self::Value, A::Error> {
for (i, el) in self.0.iter_mut().enumerate() {
*el = seq
.next_element::<u8>()?
.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::<u8>()?
.ok_or(de::Error::invalid_length(1, &"tagging byte"))?;
if first & COMPRESSED != 0 {
let len = first & !COMPRESSED;
seq.next_element_seed(RestDeserialize(&mut bytes[32 - len as usize..]))?;
} else {
bytes[0] = first;
seq.next_element_seed(RestDeserialize(&mut bytes[1..]))?;
}
Ok(Felt(bytes))
}
}
if deserializer.is_human_readable() {
deserializer.deserialize_str(FeltVisitor)
} else {
deserializer.deserialize_tuple(2, FeltVisitor) // deserialize tuple uses visit_seq in serde
}
}
}
fn main() {
let mut bytes = [0; 32];
for i in 0..32 {
bytes[32 - 1 - i] = 1;
let felt = Felt(bytes);
let bytes = bincode::serialize(&felt).unwrap();
println!("{:?} => {} bytes", felt.0, bytes.len());
let other = bincode::deserialize(&bytes).unwrap();
assert_eq!(felt, other);
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct WithOtherFields {
a: String,
b: u32,
c: Felt,
u: u32,
d: Felt,
y: String,
e: Felt,
}
let struct_ = WithOtherFields {
a: "hello world".into(),
b: 446,
c: felt,
u: 8092,
d: felt,
y: "hii".into(),
e: felt,
};
let bytes = bincode::serialize(&struct_).unwrap();
let other = bincode::deserialize(&bytes).unwrap();
assert_eq!(struct_, other);
}
}
@cchudant
Copy link
Author

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] => 2 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] => 3 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1] => 4 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] => 5 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1] => 6 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1] => 7 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] => 8 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1] => 9 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 10 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 11 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 12 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 13 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 14 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 15 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 16 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 17 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 18 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 19 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 20 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 21 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 22 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 23 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 24 bytes
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 25 bytes
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 26 bytes
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 27 bytes
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 28 bytes
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 29 bytes
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 30 bytes
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 31 bytes
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 32 bytes
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] => 32 bytes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment