Skip to content

Commit d040c9c

Browse files
committed
Update hex en/decoding functions
1 parent a019ba0 commit d040c9c

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

src/middleware/basetypes.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,22 @@ impl fmt::Display for Hash {
190190
impl FromHex for Hash {
191191
type Error = FromHexError;
192192

193-
// TODO make it dependant on backend::Value len
194193
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
195-
// In little endian
194+
// The input `hex` is a big-endian hex string.
196195
let bytes = <[u8; 32]>::from_hex(hex)?;
197-
let mut buf: [u8; 8] = [0; 8];
198196
let mut inner = [F::ZERO; HASH_SIZE];
197+
199198
for i in 0..HASH_SIZE {
200-
buf.copy_from_slice(&bytes[8 * i..8 * (i + 1)]);
201-
inner[i] = F::from_canonical_u64(u64::from_le_bytes(buf));
199+
let start = i * 8;
200+
let end = start + 8;
201+
let chunk: [u8; 8] = bytes[start..end]
202+
.try_into()
203+
.expect("slice with incorrect length");
204+
205+
// We read big-endian chunks from a big-endian string,
206+
// and place them into a little-endian limb array.
207+
let u64_val = u64::from_be_bytes(chunk);
208+
inner[HASH_SIZE - 1 - i] = F::from_canonical_u64(u64_val);
202209
}
203210
Ok(Self(inner))
204211
}

src/middleware/serialization.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::collections::{HashMap, HashSet};
1+
use std::{
2+
collections::{HashMap, HashSet},
3+
fmt::Write,
4+
};
25

36
use plonky2::field::types::Field;
47
use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
@@ -13,10 +16,16 @@ fn serialize_field_tuple<S, const N: usize>(
1316
where
1417
S: serde::Serializer,
1518
{
16-
serializer.serialize_str(&format!(
17-
"{:016x}{:016x}{:016x}{:016x}",
18-
value[0].0, value[1].0, value[2].0, value[3].0
19-
))
19+
// `value` is little-endian in memory. We serialize it as a big-endian hex string
20+
// for human readability.
21+
let s = value
22+
.iter()
23+
.rev()
24+
.fold(String::with_capacity(N * 16), |mut s, limb| {
25+
write!(s, "{:016x}", limb.0).unwrap();
26+
s
27+
});
28+
serializer.serialize_str(&s)
2029
}
2130

2231
fn deserialize_field_tuple<'de, D, const N: usize>(deserializer: D) -> Result<[F; N], D::Error>
@@ -25,20 +34,29 @@ where
2534
{
2635
let hex_str = String::deserialize(deserializer)?;
2736

28-
if !hex_str.chars().count() == 64 || !hex_str.chars().all(|c| c.is_ascii_hexdigit()) {
37+
let expected_len = N * 16;
38+
if hex_str.len() != expected_len {
39+
return Err(serde::de::Error::custom(format!(
40+
"Invalid hex string length: expected {} characters, found {}",
41+
expected_len,
42+
hex_str.len()
43+
)));
44+
}
45+
if !hex_str.chars().all(|c| c.is_ascii_hexdigit()) {
2946
return Err(serde::de::Error::custom(
30-
"Invalid hex string format - expected 64 hexadecimal characters",
47+
"Invalid hex string format: contains non-hexadecimal characters",
3148
));
3249
}
3350

3451
let mut v = [F::ZERO; N];
35-
for (i, v_i) in v.iter_mut().enumerate() {
52+
for i in 0..N {
3653
let start = i * 16;
3754
let end = start + 16;
3855
let hex_part = &hex_str[start..end];
39-
*v_i = F::from_canonical_u64(
40-
u64::from_str_radix(hex_part, 16).map_err(serde::de::Error::custom)?,
41-
);
56+
let u64_val = u64::from_str_radix(hex_part, 16).map_err(serde::de::Error::custom)?;
57+
// The hex string is big-endian, so the first chunk (i=0) is the most significant.
58+
// We store it in the last position of our little-endian array `v`.
59+
v[N - 1 - i] = F::from_canonical_u64(u64_val);
4260
}
4361
Ok(v)
4462
}

0 commit comments

Comments
 (0)