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),
|
NotAConstant(Value),
|
||||||
#[error("The evaluation never reached a final state")]
|
#[error("The evaluation never reached a final state")]
|
||||||
MachineNeverReachedDone,
|
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")]
|
#[error("Decoding utf8")]
|
||||||
Utf8(#[from] FromUtf8Error),
|
Utf8(#[from] FromUtf8Error),
|
||||||
#[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)]
|
#[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_bigint::BigInt;
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
|
use num_traits::{Signed, ToBytes, Zero};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use pallas::ledger::primitives::babbage::{Language, PlutusData};
|
use pallas::ledger::primitives::babbage::{Language, PlutusData};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{Constant, Data, Type},
|
ast::{Constant, Data, Type},
|
||||||
builtins::DefaultFunction,
|
builtins::DefaultFunction,
|
||||||
|
machine::value::integer_log2,
|
||||||
plutus_data_to_bytes,
|
plutus_data_to_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,6 +34,8 @@ const BLST_P1_COMPRESSED_SIZE: usize = 48;
|
||||||
|
|
||||||
const BLST_P2_COMPRESSED_SIZE: usize = 96;
|
const BLST_P2_COMPRESSED_SIZE: usize = 96;
|
||||||
|
|
||||||
|
const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192;
|
||||||
|
|
||||||
//#[derive(std::cmp::PartialEq)]
|
//#[derive(std::cmp::PartialEq)]
|
||||||
//pub enum EvalMode {
|
//pub enum EvalMode {
|
||||||
// Immediate,
|
// Immediate,
|
||||||
|
@ -1298,6 +1302,80 @@ impl DefaultFunction {
|
||||||
|
|
||||||
Ok(Value::Con(constant.into()))
|
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 std::{collections::VecDeque, mem::size_of, ops::Deref, rc::Rc};
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_traits::{Signed, ToPrimitive};
|
use num_traits::{Signed, ToPrimitive, Zero};
|
||||||
use pallas::ledger::primitives::babbage::{self, PlutusData};
|
use pallas::ledger::primitives::babbage::{self, PlutusData};
|
||||||
|
|
||||||
use crate::{
|
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();
|
let (_, bytes) = i.to_bytes_be();
|
||||||
|
|
||||||
match bytes.first() {
|
match bytes.first() {
|
||||||
None => unreachable!("empty number?"),
|
None => unreachable!("empty number?"),
|
||||||
Some(u) => (8 - u.leading_zeros() - 1) as i64 + 8 * (bytes.len() - 1) as i64,
|
Some(u) => (8 - u.leading_zeros() - 1) as i64 + 8 * (bytes.len() - 1) as i64,
|
||||||
|
@ -524,6 +529,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn integer_log2_oracle() {
|
fn integer_log2_oracle() {
|
||||||
// Values come from the Haskell implementation
|
// Values come from the Haskell implementation
|
||||||
|
assert_eq!(integer_log2(0.into()), 0);
|
||||||
assert_eq!(integer_log2(1.into()), 0);
|
assert_eq!(integer_log2(1.into()), 0);
|
||||||
assert_eq!(integer_log2(42.into()), 5);
|
assert_eq!(integer_log2(42.into()), 5);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in New Issue