A few more left to finish

This commit is contained in:
microproofs 2024-12-01 14:21:32 +07:00
parent c3b6bc5bff
commit 9867de38b6
No known key found for this signature in database
GPG Key ID: 14F93C84DE6AFD17
4 changed files with 128 additions and 22 deletions

View File

@ -2538,8 +2538,8 @@ impl BuiltinCosts {
.cpu .cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()), .cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
}, },
DefaultFunction::IntegerToByteString => { d @ DefaultFunction::IntegerToByteString => {
let size = args[1].cost_as_size()?; let size = args[1].cost_as_size(d)?;
ExBudget { ExBudget {
mem: self.integer_to_byte_string.mem.cost( mem: self.integer_to_byte_string.mem.cost(
@ -2630,8 +2630,8 @@ impl BuiltinCosts {
), ),
} }
} }
DefaultFunction::ReplicateByte => { d @ DefaultFunction::ReplicateByte => {
let size = args[0].cost_as_size()?; let size = args[0].cost_as_size(d)?;
ExBudget { ExBudget {
mem: self.replicate_byte.mem.cost(size, args[1].to_ex_mem()), mem: self.replicate_byte.mem.cost(size, args[1].to_ex_mem()),

View File

@ -120,10 +120,14 @@ pub enum Error {
DeserialisationError(String, Value), DeserialisationError(String, Value),
#[error("integer overflow")] #[error("integer overflow")]
OverflowError, OverflowError,
#[error("{0} is not within the bounds of Natural")] #[error("{0} is not within the bounds of a Natural")]
OutsideNaturalBounds(BigInt), OutsideNaturalBounds(BigInt),
#[error("{0} is not within the bounds of a Byte")]
OutsideByteBounds(BigInt),
#[error("readBit: index out of bounds")] #[error("readBit: index out of bounds")]
ReadBitOutOfBounds, ReadBitOutOfBounds,
#[error("writeBits: index out of bounds")]
WriteBitsOutOfBounds,
#[error("blst error {0:?}")] #[error("blst error {0:?}")]
Blst(blst::BLST_ERROR), Blst(blst::BLST_ERROR),
#[error("blst::hashToGroup")] #[error("blst::hashToGroup")]

View File

@ -10,12 +10,12 @@ use crate::{
plutus_data_to_bytes, plutus_data_to_bytes,
}; };
use itertools::Itertools; use itertools::Itertools;
use num_bigint::BigInt; use num_bigint::{BigInt, Sign};
use num_integer::Integer; use num_integer::Integer;
use num_traits::{Signed, Zero}; use num_traits::{FromPrimitive, Signed, Zero};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use pallas_primitives::conway::{Language, PlutusData}; use pallas_primitives::conway::{Language, PlutusData};
use std::{mem::size_of, ops::Deref, rc::Rc}; use std::{io::Read, mem::size_of, ops::Deref, rc::Rc};
static SCALAR_PERIOD: Lazy<BigInt> = Lazy::new(|| { static SCALAR_PERIOD: Lazy<BigInt> = Lazy::new(|| {
BigInt::from_bytes_be( BigInt::from_bytes_be(
@ -1522,7 +1522,7 @@ impl DefaultFunction {
.collect_vec() .collect_vec()
}; };
Ok(Value::Con(Constant::ByteString(bytes_result).into())) Ok(Value::byte_string(bytes_result))
} }
DefaultFunction::OrByteString => { DefaultFunction::OrByteString => {
let should_pad = args[0].unwrap_bool()?; let should_pad = args[0].unwrap_bool()?;
@ -1550,7 +1550,7 @@ impl DefaultFunction {
.collect_vec() .collect_vec()
}; };
Ok(Value::Con(Constant::ByteString(bytes_result).into())) Ok(Value::byte_string(bytes_result))
} }
DefaultFunction::XorByteString => { DefaultFunction::XorByteString => {
let should_pad = args[0].unwrap_bool()?; let should_pad = args[0].unwrap_bool()?;
@ -1578,14 +1578,14 @@ impl DefaultFunction {
.collect_vec() .collect_vec()
}; };
Ok(Value::Con(Constant::ByteString(bytes_result).into())) Ok(Value::byte_string(bytes_result))
} }
DefaultFunction::ComplementByteString => { DefaultFunction::ComplementByteString => {
let bytes = args[0].unwrap_byte_string()?; let bytes = args[0].unwrap_byte_string()?;
let result = bytes.into_iter().map(|b| b ^ 255).collect_vec(); let result = bytes.into_iter().map(|b| b ^ 255).collect_vec();
Ok(Value::Con(Constant::ByteString(result).into())) Ok(Value::byte_string(result))
} }
DefaultFunction::ReadBit => { DefaultFunction::ReadBit => {
let bytes = args[0].unwrap_byte_string()?; let bytes = args[0].unwrap_byte_string()?;
@ -1606,11 +1606,88 @@ impl DefaultFunction {
let bit_test = (byte >> bit_offset) & 1 == 1; let bit_test = (byte >> bit_offset) & 1 == 1;
Ok(Value::Con(Constant::Bool(bit_test).into())) Ok(Value::bool(bit_test))
}
DefaultFunction::WriteBits => {
let mut bytes = args[0].unwrap_byte_string()?.clone();
let indices = args[1].unwrap_int_list()?;
let set_bit = args[2].unwrap_bool()?;
for index in indices {
let Constant::Integer(bit_index) = index else {
unreachable!()
};
if *bit_index < 0.into() || *bit_index >= (bytes.len() * 8).into() {
return Err(Error::WriteBitsOutOfBounds);
}
let (byte_index, bit_offset) = bit_index.div_rem(&8.into());
let bit_offset = usize::try_from(bit_offset).unwrap();
let flipped_index = bytes.len() - 1 - usize::try_from(byte_index).unwrap();
let bit_mask: u8 = 1 >> bit_offset;
if *set_bit {
bytes[flipped_index] |= bit_mask;
} else {
bytes[flipped_index] &= !bit_mask;
}
}
Ok(Value::byte_string(bytes))
}
DefaultFunction::ReplicateByte => {
let size = args[0].unwrap_integer()?;
let byte = args[1].unwrap_integer()?;
// Safe since this is checked by cost model
let size = usize::try_from(size).unwrap();
let Ok(byte) = u8::try_from(byte) else {
return Err(Error::OutsideByteBounds(byte.clone()));
};
let value = if size == 0 {
Value::byte_string(vec![])
} else {
Value::byte_string([byte].repeat(size - 1))
};
Ok(value)
}
DefaultFunction::ShiftByteString => {
let bytes = args[0].unwrap_byte_string()?;
let shift = args[1].unwrap_integer()?;
let byte_length = bytes.len();
if BigInt::from_usize(byte_length).unwrap() * 8 < shift.abs() {
let mut new_vec = vec![];
new_vec.resize(byte_length, 0);
return Ok(Value::byte_string(new_vec));
}
let bytes = BigInt::from_bytes_be(Sign::NoSign, bytes);
let is_shl = shift >= &0.into();
let bytes = if is_shl {
bytes << usize::try_from(shift.abs()).unwrap()
} else {
bytes >> usize::try_from(shift.abs()).unwrap()
}
.to_bytes_be()
.1
.into_iter()
.take(byte_length)
.collect_vec();
Ok(Value::byte_string(bytes))
} }
DefaultFunction::WriteBits => todo!(),
DefaultFunction::ReplicateByte => todo!(),
DefaultFunction::ShiftByteString => todo!(),
DefaultFunction::RotateByteString => todo!(), DefaultFunction::RotateByteString => todo!(),
DefaultFunction::CountSetBits => todo!(), DefaultFunction::CountSetBits => todo!(),
DefaultFunction::FindFirstSetBit => todo!(), DefaultFunction::FindFirstSetBit => todo!(),

View File

@ -173,6 +173,19 @@ impl Value {
Ok(list) Ok(list)
} }
pub(super) fn unwrap_int_list(&self) -> Result<&Vec<Constant>, Error> {
let inner = self.unwrap_constant()?;
let Constant::ProtoList(Type::Integer, list) = inner else {
return Err(Error::TypeMismatch(
Type::List(Type::Integer.into()),
inner.into(),
));
};
Ok(list)
}
pub(super) fn unwrap_bls12_381_g1_element(&self) -> Result<&blst::blst_p1, Error> { pub(super) fn unwrap_bls12_381_g1_element(&self) -> Result<&blst::blst_p1, Error> {
let inner = self.unwrap_constant()?; let inner = self.unwrap_constant()?;
@ -211,18 +224,30 @@ impl Value {
matches!(self, Value::Con(b) if matches!(b.as_ref(), Constant::Bool(_))) matches!(self, Value::Con(b) if matches!(b.as_ref(), Constant::Bool(_)))
} }
pub fn cost_as_size(&self) -> Result<i64, Error> { pub fn cost_as_size(&self, func: DefaultFunction) -> Result<i64, Error> {
let size = self.unwrap_integer()?; let size = self.unwrap_integer()?;
if size.is_negative() { if size.is_negative() {
return Err(Error::IntegerToByteStringNegativeSize(size.clone())); let error = match func {
DefaultFunction::IntegerToByteString => {
Error::IntegerToByteStringNegativeSize(size.clone())
}
DefaultFunction::ReplicateByte => todo!(),
_ => unreachable!(),
};
return Err(error);
} }
if size > &BigInt::from(runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH) { if size > &BigInt::from(runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH) {
return Err(Error::IntegerToByteStringSizeTooBig( let error = match func {
size.clone(), DefaultFunction::IntegerToByteString => Error::IntegerToByteStringSizeTooBig(
runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH, size.clone(),
)); runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH,
),
DefaultFunction::ReplicateByte => todo!(),
_ => unreachable!(),
};
return Err(error);
} }
let arg1: i64 = u64::try_from(size).unwrap().try_into().unwrap(); let arg1: i64 = u64::try_from(size).unwrap().try_into().unwrap();