feat: implement integerToByteString
Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
parent
c7dd4d0e48
commit
da6e5ec6d1
|
@ -40,7 +40,14 @@ pub enum Error {
|
|||
NotAConstant(Value),
|
||||
#[error("The evaluation never reached a final state")]
|
||||
MachineNeverReachedDone,
|
||||
|
||||
#[error("integerToByteString encountered negative size {0}")]
|
||||
IntegerToByteStringNegativeSize(BigInt),
|
||||
#[error("integerToByteString encountered negative input {0}")]
|
||||
IntegerToByteStringNegativeInput(BigInt),
|
||||
#[error("integerToByteString encountered size {0} which is bigger than the max size of {1}")]
|
||||
IntegerToByteStringSizeTooBig(BigInt, i64),
|
||||
#[error("integerToByteString encountered size {0} which is not enough space for {1} bytes")]
|
||||
IntegerToByteStringSizeTooSmall(BigInt, usize),
|
||||
#[error("Decoding utf8")]
|
||||
Utf8(#[from] FromUtf8Error),
|
||||
#[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)]
|
||||
|
|
|
@ -2,12 +2,14 @@ use std::{mem::size_of, ops::Deref, rc::Rc};
|
|||
|
||||
use num_bigint::BigInt;
|
||||
use num_integer::Integer;
|
||||
use num_traits::{Signed, ToBytes, Zero};
|
||||
use once_cell::sync::Lazy;
|
||||
use pallas::ledger::primitives::babbage::{Language, PlutusData};
|
||||
|
||||
use crate::{
|
||||
ast::{Constant, Data, Type},
|
||||
builtins::DefaultFunction,
|
||||
machine::value::integer_log2,
|
||||
plutus_data_to_bytes,
|
||||
};
|
||||
|
||||
|
@ -32,6 +34,8 @@ const BLST_P1_COMPRESSED_SIZE: usize = 48;
|
|||
|
||||
const BLST_P2_COMPRESSED_SIZE: usize = 96;
|
||||
|
||||
const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192;
|
||||
|
||||
//#[derive(std::cmp::PartialEq)]
|
||||
//pub enum EvalMode {
|
||||
// Immediate,
|
||||
|
@ -1298,6 +1302,80 @@ impl DefaultFunction {
|
|||
|
||||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::IntegerToByteString => {
|
||||
let endianness = args[0].unwrap_bool()?;
|
||||
let size = args[1].unwrap_integer()?;
|
||||
let input = args[2].unwrap_integer()?;
|
||||
|
||||
if size.is_negative() {
|
||||
return Err(Error::IntegerToByteStringNegativeSize(size.clone()));
|
||||
}
|
||||
|
||||
if size > &INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH.into() {
|
||||
return Err(Error::IntegerToByteStringSizeTooBig(
|
||||
size.clone(),
|
||||
INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH,
|
||||
));
|
||||
}
|
||||
|
||||
if size.is_zero()
|
||||
&& integer_log2(input.clone())
|
||||
>= 8 * INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH
|
||||
{
|
||||
let required = integer_log2(input.clone()) / 8 + 1;
|
||||
|
||||
return Err(Error::IntegerToByteStringSizeTooBig(
|
||||
required.into(),
|
||||
INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH,
|
||||
));
|
||||
}
|
||||
|
||||
if input.is_negative() {
|
||||
return Err(Error::IntegerToByteStringNegativeInput(input.clone()));
|
||||
}
|
||||
|
||||
let size_unwrapped: usize = size.try_into().unwrap();
|
||||
|
||||
if input.is_zero() {
|
||||
let constant = Constant::ByteString(vec![0; size_unwrapped]);
|
||||
|
||||
return Ok(Value::Con(constant.into()));
|
||||
}
|
||||
|
||||
let mut bytes = if *endianness {
|
||||
input.to_be_bytes()
|
||||
} else {
|
||||
input.to_le_bytes()
|
||||
};
|
||||
|
||||
if !size.is_zero() && bytes.len() > size_unwrapped {
|
||||
return Err(Error::IntegerToByteStringSizeTooSmall(
|
||||
size.clone(),
|
||||
bytes.len(),
|
||||
));
|
||||
}
|
||||
|
||||
if size_unwrapped > 0 {
|
||||
let padding_size = size_unwrapped - bytes.len();
|
||||
|
||||
let mut padding = vec![0; padding_size];
|
||||
|
||||
if *endianness {
|
||||
padding.append(&mut bytes);
|
||||
|
||||
bytes = padding;
|
||||
} else {
|
||||
bytes.append(&mut padding);
|
||||
}
|
||||
};
|
||||
|
||||
let constant = Constant::ByteString(bytes);
|
||||
|
||||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::ByteStringToInteger => {
|
||||
todo!("do it not live")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::VecDeque, mem::size_of, ops::Deref, rc::Rc};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::{Signed, ToPrimitive};
|
||||
use num_traits::{Signed, ToPrimitive, Zero};
|
||||
use pallas::ledger::primitives::babbage::{self, PlutusData};
|
||||
|
||||
use crate::{
|
||||
|
@ -386,8 +386,13 @@ impl TryFrom<&Value> for Constant {
|
|||
}
|
||||
}
|
||||
|
||||
fn integer_log2(i: BigInt) -> i64 {
|
||||
pub fn integer_log2(i: BigInt) -> i64 {
|
||||
if i.is_zero() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let (_, bytes) = i.to_bytes_be();
|
||||
|
||||
match bytes.first() {
|
||||
None => unreachable!("empty number?"),
|
||||
Some(u) => (8 - u.leading_zeros() - 1) as i64 + 8 * (bytes.len() - 1) as i64,
|
||||
|
@ -524,6 +529,7 @@ mod tests {
|
|||
#[test]
|
||||
fn integer_log2_oracle() {
|
||||
// Values come from the Haskell implementation
|
||||
assert_eq!(integer_log2(0.into()), 0);
|
||||
assert_eq!(integer_log2(1.into()), 0);
|
||||
assert_eq!(integer_log2(42.into()), 5);
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in New Issue