Podlog language v1 (#225)
* Initial commit for Podlog language * Spell-checker thinks that 'lits' is a bad abbreviation for 'literals' * Enable SetContains/SetNotContains * Update language based on review feedback * Typo/comment fix * Make native predicates case-sensitive * Enforce max batch size in CustomPredicateBatchBuilder * Remove some unnecessary checks for things handled by the grammar * Clean up more unnecessary error-checking * Typo * Simplify hex processing * Replace various errors with unreachable!() * Translate from big-endian hex string to little-endian RawValue * Update hex en/decoding functions
This commit is contained in:
parent
e8edbbc1c5
commit
541c264586
11 changed files with 2259 additions and 29 deletions
|
|
@ -190,15 +190,22 @@ impl fmt::Display for Hash {
|
|||
impl FromHex for Hash {
|
||||
type Error = FromHexError;
|
||||
|
||||
// TODO make it dependant on backend::Value len
|
||||
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
|
||||
// In little endian
|
||||
// The input `hex` is a big-endian hex string.
|
||||
let bytes = <[u8; 32]>::from_hex(hex)?;
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let mut inner = [F::ZERO; HASH_SIZE];
|
||||
|
||||
for i in 0..HASH_SIZE {
|
||||
buf.copy_from_slice(&bytes[8 * i..8 * (i + 1)]);
|
||||
inner[i] = F::from_canonical_u64(u64::from_le_bytes(buf));
|
||||
let start = i * 8;
|
||||
let end = start + 8;
|
||||
let chunk: [u8; 8] = bytes[start..end]
|
||||
.try_into()
|
||||
.expect("slice with incorrect length");
|
||||
|
||||
// We read big-endian chunks from a big-endian string,
|
||||
// and place them into a little-endian limb array.
|
||||
let u64_val = u64::from_be_bytes(chunk);
|
||||
inner[HASH_SIZE - 1 - i] = F::from_canonical_u64(u64_val);
|
||||
}
|
||||
Ok(Self(inner))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -373,20 +373,12 @@ impl fmt::Display for CustomPredicate {
|
|||
pub struct CustomPredicateBatch {
|
||||
id: Hash,
|
||||
pub name: String,
|
||||
predicates: Vec<CustomPredicate>,
|
||||
pub(crate) predicates: Vec<CustomPredicate>,
|
||||
}
|
||||
|
||||
impl ToFields for CustomPredicateBatch {
|
||||
fn to_fields(&self, params: &Params) -> Vec<F> {
|
||||
// all the custom predicates in order
|
||||
|
||||
// TODO think if this check should go into the StatementTmpl creation,
|
||||
// instead of at the `to_fields` method, where we should assume that the
|
||||
// values are already valid
|
||||
if self.predicates.len() > params.max_custom_batch_size {
|
||||
panic!("Predicate batch exceeds maximum size");
|
||||
}
|
||||
|
||||
let pad_pred = CustomPredicate::empty();
|
||||
let fields: Vec<F> = self
|
||||
.predicates
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Write,
|
||||
};
|
||||
|
||||
use plonky2::field::types::Field;
|
||||
use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
|
||||
|
|
@ -13,10 +16,16 @@ fn serialize_field_tuple<S, const N: usize>(
|
|||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&format!(
|
||||
"{:016x}{:016x}{:016x}{:016x}",
|
||||
value[0].0, value[1].0, value[2].0, value[3].0
|
||||
))
|
||||
// `value` is little-endian in memory. We serialize it as a big-endian hex string
|
||||
// for human readability.
|
||||
let s = value
|
||||
.iter()
|
||||
.rev()
|
||||
.fold(String::with_capacity(N * 16), |mut s, limb| {
|
||||
write!(s, "{:016x}", limb.0).unwrap();
|
||||
s
|
||||
});
|
||||
serializer.serialize_str(&s)
|
||||
}
|
||||
|
||||
fn deserialize_field_tuple<'de, D, const N: usize>(deserializer: D) -> Result<[F; N], D::Error>
|
||||
|
|
@ -25,20 +34,29 @@ where
|
|||
{
|
||||
let hex_str = String::deserialize(deserializer)?;
|
||||
|
||||
if !hex_str.chars().count() == 64 || !hex_str.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
let expected_len = N * 16;
|
||||
if hex_str.len() != expected_len {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"Invalid hex string length: expected {} characters, found {}",
|
||||
expected_len,
|
||||
hex_str.len()
|
||||
)));
|
||||
}
|
||||
if !hex_str.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
return Err(serde::de::Error::custom(
|
||||
"Invalid hex string format - expected 64 hexadecimal characters",
|
||||
"Invalid hex string format: contains non-hexadecimal characters",
|
||||
));
|
||||
}
|
||||
|
||||
let mut v = [F::ZERO; N];
|
||||
for (i, v_i) in v.iter_mut().enumerate() {
|
||||
for i in 0..N {
|
||||
let start = i * 16;
|
||||
let end = start + 16;
|
||||
let hex_part = &hex_str[start..end];
|
||||
*v_i = F::from_canonical_u64(
|
||||
u64::from_str_radix(hex_part, 16).map_err(serde::de::Error::custom)?,
|
||||
);
|
||||
let u64_val = u64::from_str_radix(hex_part, 16).map_err(serde::de::Error::custom)?;
|
||||
// The hex string is big-endian, so the first chunk (i=0) is the most significant.
|
||||
// We store it in the last position of our little-endian array `v`.
|
||||
v[N - 1 - i] = F::from_canonical_u64(u64_val);
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue