feat: Implemented builtin semantic versioning

feat: impl flat serialization and deserialization for bls constants
feat: started on cost models for the new builtins

Co-authored-by: rvcas <x@rvcas.dev>
This commit is contained in:
microproofs 2023-11-02 22:46:59 -04:00 committed by Lucas
parent f101581813
commit 18db1c394a
5 changed files with 338 additions and 500 deletions

View File

@ -3,8 +3,11 @@ use crate::{
Constant, DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term, Type, Unique, Constant, DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term, Type, Unique,
}, },
builtins::DefaultFunction, builtins::DefaultFunction,
machine::runtime::Compressable,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use flat_rs::{ use flat_rs::{
de::{self, Decode, Decoder}, de::{self, Decode, Decoder},
en::{self, Encode, Encoder}, en::{self, Encode, Encoder},
@ -487,9 +490,27 @@ impl Encode for Constant {
cbor.encode(e)?; cbor.encode(e)?;
} }
Constant::Bls12_381G1Element(_) => todo!(), Constant::Bls12_381G1Element(b) => {
Constant::Bls12_381G2Element(_) => todo!(), encode_constant(&[9], e)?;
Constant::Bls12_381MlResult(_) => todo!(),
let x = b.compress();
x.encode(e)?;
}
Constant::Bls12_381G2Element(b) => {
encode_constant(&[10], e)?;
let x = b.compress();
x.encode(e)?;
}
Constant::Bls12_381MlResult(_) => {
encode_constant(&[11], e)?;
return Err(en::Error::Message(
"BLS12-381 ML results are not supported for flat encoding".to_string(),
));
}
} }
Ok(()) Ok(())
@ -523,19 +544,29 @@ fn encode_constant_value(x: &Constant, e: &mut Encoder) -> Result<(), en::Error>
cbor.encode(e) cbor.encode(e)
} }
Constant::Bls12_381G1Element(_) => todo!(), Constant::Bls12_381G1Element(b) => {
Constant::Bls12_381G2Element(_) => todo!(), let x = b.compress();
Constant::Bls12_381MlResult(_) => todo!(),
x.encode(e)
}
Constant::Bls12_381G2Element(b) => {
let x = b.compress();
x.encode(e)
}
Constant::Bls12_381MlResult(_) => Err(en::Error::Message(
"BLS12-381 ML results are not supported for flat encoding".to_string(),
)),
} }
} }
fn encode_type(typ: &Type, bytes: &mut Vec<u8>) { fn encode_type(typ: &Type, bytes: &mut Vec<u8>) {
match typ { match typ {
Type::Bool => bytes.push(4),
Type::Integer => bytes.push(0), Type::Integer => bytes.push(0),
Type::String => bytes.push(2),
Type::ByteString => bytes.push(1), Type::ByteString => bytes.push(1),
Type::String => bytes.push(2),
Type::Unit => bytes.push(3), Type::Unit => bytes.push(3),
Type::Bool => bytes.push(4),
Type::List(sub_typ) => { Type::List(sub_typ) => {
bytes.extend(vec![7, 5]); bytes.extend(vec![7, 5]);
encode_type(sub_typ, bytes); encode_type(sub_typ, bytes);
@ -546,9 +577,9 @@ fn encode_type(typ: &Type, bytes: &mut Vec<u8>) {
encode_type(type2, bytes); encode_type(type2, bytes);
} }
Type::Data => bytes.push(8), Type::Data => bytes.push(8),
Type::Bls12_381G1Element => todo!(), Type::Bls12_381G1Element => bytes.push(9),
Type::Bls12_381G2Element => todo!(), Type::Bls12_381G2Element => bytes.push(10),
Type::Bls12_381MlResult => todo!(), Type::Bls12_381MlResult => bytes.push(11),
} }
} }
@ -589,6 +620,28 @@ impl<'b> Decode<'b> for Constant {
Ok(Constant::Data(data)) Ok(Constant::Data(data))
} }
[9] => {
let p1 = Vec::<u8>::decode(d)?;
let p1 = blst::blst_p1::uncompress(&p1).map_err(|err| {
de::Error::Message(format!("Failed to uncompress p1: {}", err))
})?;
Ok(Constant::Bls12_381G1Element(p1.into()))
}
[10] => {
let p2 = Vec::<u8>::decode(d)?;
let p2 = blst::blst_p2::uncompress(&p2).map_err(|err| {
de::Error::Message(format!("Failed to uncompress p2: {}", err))
})?;
Ok(Constant::Bls12_381G2Element(p2.into()))
}
[11] => Err(de::Error::Message(
"BLS12-381 ML results are not supported for flat decoding".to_string(),
)),
x => Err(de::Error::Message(format!( x => Err(de::Error::Message(format!(
"Unknown constant constructor tag: {x:?}" "Unknown constant constructor tag: {x:?}"
))), ))),
@ -628,9 +681,25 @@ fn decode_constant_value(typ: Rc<Type>, d: &mut Decoder) -> Result<Constant, de:
Ok(Constant::Data(data)) Ok(Constant::Data(data))
} }
Type::Bls12_381G1Element => todo!(), Type::Bls12_381G1Element => {
Type::Bls12_381G2Element => todo!(), let p1 = Vec::<u8>::decode(d)?;
Type::Bls12_381MlResult => todo!(),
let p1 = blst::blst_p1::uncompress(&p1)
.map_err(|err| de::Error::Message(format!("Failed to uncompress p1: {}", err)))?;
Ok(Constant::Bls12_381G1Element(p1.into()))
}
Type::Bls12_381G2Element => {
let p2 = Vec::<u8>::decode(d)?;
let p2 = blst::blst_p2::uncompress(&p2)
.map_err(|err| de::Error::Message(format!("Failed to uncompress p2: {}", err)))?;
Ok(Constant::Bls12_381G2Element(p2.into()))
}
Type::Bls12_381MlResult => Err(de::Error::Message(
"BLS12-381 ML results are not supported for flat decoding".to_string(),
)),
} }
} }
@ -642,6 +711,9 @@ fn decode_type(types: &mut VecDeque<u8>) -> Result<Type, de::Error> {
Some(1) => Ok(Type::ByteString), Some(1) => Ok(Type::ByteString),
Some(3) => Ok(Type::Unit), Some(3) => Ok(Type::Unit),
Some(8) => Ok(Type::Data), Some(8) => Ok(Type::Data),
Some(9) => Ok(Type::Bls12_381G1Element),
Some(10) => Ok(Type::Bls12_381G2Element),
Some(11) => Ok(Type::Bls12_381MlResult),
Some(7) => match types.pop_front() { Some(7) => match types.pop_front() {
Some(5) => Ok(Type::List(decode_type(types)?.into())), Some(5) => Ok(Type::List(decode_type(types)?.into())),
Some(7) => match types.pop_front() { Some(7) => match types.pop_front() {

View File

@ -315,14 +315,11 @@ impl Machine {
} }
fn eval_builtin_app(&mut self, runtime: BuiltinRuntime) -> Result<Value, Error> { fn eval_builtin_app(&mut self, runtime: BuiltinRuntime) -> Result<Value, Error> {
let cost = match self.version { let cost = runtime.to_ex_budget(&self.costs.builtin_costs);
Language::PlutusV1 => runtime.to_ex_budget_v1(&self.costs.builtin_costs),
Language::PlutusV2 => runtime.to_ex_budget_v2(&self.costs.builtin_costs),
};
self.spend_budget(cost)?; self.spend_budget(cost)?;
runtime.call(&mut self.logs) runtime.call(&self.version, &mut self.logs)
} }
fn lookup_var(&mut self, name: &NamedDeBruijn, env: &[Value]) -> Result<Value, Error> { fn lookup_var(&mut self, name: &NamedDeBruijn, env: &[Value]) -> Result<Value, Error> {

View File

@ -228,7 +228,9 @@ pub struct BuiltinCosts {
// Cryptography and hashes // Cryptography and hashes
pub sha2_256: CostingFun<OneArgument>, pub sha2_256: CostingFun<OneArgument>,
pub sha3_256: CostingFun<OneArgument>, pub sha3_256: CostingFun<OneArgument>,
pub blake2b_224: CostingFun<OneArgument>,
pub blake2b_256: CostingFun<OneArgument>, pub blake2b_256: CostingFun<OneArgument>,
pub keccak_256: CostingFun<OneArgument>,
pub verify_ed25519_signature: CostingFun<ThreeArguments>, pub verify_ed25519_signature: CostingFun<ThreeArguments>,
pub verify_ecdsa_secp256k1_signature: CostingFun<ThreeArguments>, pub verify_ecdsa_secp256k1_signature: CostingFun<ThreeArguments>,
pub verify_schnorr_secp256k1_signature: CostingFun<ThreeArguments>, pub verify_schnorr_secp256k1_signature: CostingFun<ThreeArguments>,
@ -270,6 +272,24 @@ pub struct BuiltinCosts {
pub mk_nil_data: CostingFun<OneArgument>, pub mk_nil_data: CostingFun<OneArgument>,
pub mk_nil_pair_data: CostingFun<OneArgument>, pub mk_nil_pair_data: CostingFun<OneArgument>,
pub serialise_data: CostingFun<OneArgument>, pub serialise_data: CostingFun<OneArgument>,
// BLST
bls12_381_g1_add: CostingFun<TwoArguments>,
bls12_381_g1_neg: CostingFun<OneArgument>,
bls12_381_g1_scalarmul: CostingFun<TwoArguments>,
bls12_381_g1_equal: CostingFun<TwoArguments>,
bls12_381_g1_compress: CostingFun<OneArgument>,
bls12_381_g1_uncompress: CostingFun<OneArgument>,
bls12_381_g1_hashtogroup: CostingFun<TwoArguments>,
bls12_381_g2_add: CostingFun<TwoArguments>,
bls12_381_g2_neg: CostingFun<OneArgument>,
bls12_381_g2_scalarmul: CostingFun<TwoArguments>,
bls12_381_g2_equal: CostingFun<TwoArguments>,
bls12_381_g2_compress: CostingFun<OneArgument>,
bls12_381_g2_uncompress: CostingFun<OneArgument>,
bls12_381_g2_hashtogroup: CostingFun<TwoArguments>,
bls12_381_millerloop: CostingFun<TwoArguments>,
bls12_381_mulmlresult: CostingFun<TwoArguments>,
bls12_381_finalverify: CostingFun<TwoArguments>,
} }
impl BuiltinCosts { impl BuiltinCosts {
@ -457,6 +477,16 @@ impl BuiltinCosts {
slope: 82523, slope: 82523,
}), }),
}, },
blake2b_224: CostingFun {
mem: OneArgument::LinearCost(LinearSize {
intercept: 30000000000,
slope: 30000000000,
}),
cpu: OneArgument::LinearCost(LinearSize {
intercept: 30000000000,
slope: 30000000000,
}),
},
blake2b_256: CostingFun { blake2b_256: CostingFun {
mem: OneArgument::ConstantCost(4), mem: OneArgument::ConstantCost(4),
cpu: OneArgument::LinearCost(LinearSize { cpu: OneArgument::LinearCost(LinearSize {
@ -464,6 +494,16 @@ impl BuiltinCosts {
slope: 10475, slope: 10475,
}), }),
}, },
keccak_256: CostingFun {
mem: OneArgument::LinearCost(LinearSize {
intercept: 30000000000,
slope: 30000000000,
}),
cpu: OneArgument::LinearCost(LinearSize {
intercept: 30000000000,
slope: 30000000000,
}),
},
verify_ed25519_signature: CostingFun { verify_ed25519_signature: CostingFun {
mem: ThreeArguments::ConstantCost(10), mem: ThreeArguments::ConstantCost(10),
cpu: ThreeArguments::LinearInZ(LinearSize { cpu: ThreeArguments::LinearInZ(LinearSize {
@ -633,6 +673,74 @@ impl BuiltinCosts {
slope: 30000000000, slope: 30000000000,
}), }),
}, },
bls12_381_g1_add: CostingFun {
mem: TwoArguments::ConstantCost(18),
cpu: TwoArguments::ConstantCost(1046420),
},
bls12_381_g1_neg: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g1_scalarmul: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g1_equal: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g1_compress: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g1_uncompress: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g1_hashtogroup: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g2_add: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g2_neg: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g2_scalarmul: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g2_equal: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g2_compress: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g2_uncompress: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_g2_hashtogroup: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_millerloop: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_mulmlresult: CostingFun {
mem: todo!(),
cpu: todo!(),
},
bls12_381_finalverify: CostingFun {
mem: todo!(),
cpu: todo!(),
},
} }
} }
} }
@ -999,12 +1107,31 @@ impl Default for BuiltinCosts {
slope: 392670, slope: 392670,
}), }),
}, },
blake2b_224: todo!(),
keccak_256: todo!(),
bls12_381_g1_add: todo!(),
bls12_381_g1_neg: todo!(),
bls12_381_g1_scalarmul: todo!(),
bls12_381_g1_equal: todo!(),
bls12_381_g1_compress: todo!(),
bls12_381_g1_uncompress: todo!(),
bls12_381_g1_hashtogroup: todo!(),
bls12_381_g2_add: todo!(),
bls12_381_g2_neg: todo!(),
bls12_381_g2_scalarmul: todo!(),
bls12_381_g2_equal: todo!(),
bls12_381_g2_compress: todo!(),
bls12_381_g2_uncompress: todo!(),
bls12_381_g2_hashtogroup: todo!(),
bls12_381_millerloop: todo!(),
bls12_381_mulmlresult: todo!(),
bls12_381_finalverify: todo!(),
} }
} }
} }
impl BuiltinCosts { impl BuiltinCosts {
pub fn to_ex_budget_v2(&self, fun: DefaultFunction, args: &[Value]) -> ExBudget { pub fn to_ex_budget(&self, fun: DefaultFunction, args: &[Value]) -> ExBudget {
match fun { match fun {
DefaultFunction::AddInteger => ExBudget { DefaultFunction::AddInteger => ExBudget {
mem: self mem: self
@ -1449,427 +1576,6 @@ impl BuiltinCosts {
DefaultFunction::Bls12_381_FinalVerify => todo!(), DefaultFunction::Bls12_381_FinalVerify => todo!(),
} }
} }
pub fn to_ex_budget_v1(&self, fun: DefaultFunction, args: &[Value]) -> ExBudget {
match fun {
DefaultFunction::AddInteger => ExBudget {
mem: self
.add_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.add_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::SubtractInteger => ExBudget {
mem: self
.subtract_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.subtract_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::MultiplyInteger => ExBudget {
mem: self
.multiply_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.multiply_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::DivideInteger => ExBudget {
mem: self
.divide_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.divide_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::QuotientInteger => ExBudget {
mem: self
.quotient_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.quotient_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::RemainderInteger => ExBudget {
mem: self
.remainder_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.remainder_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::ModInteger => ExBudget {
mem: self
.mod_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.mod_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::EqualsInteger => ExBudget {
mem: self
.equals_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.equals_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::LessThanInteger => ExBudget {
mem: self
.less_than_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.less_than_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::LessThanEqualsInteger => ExBudget {
mem: self
.less_than_equals_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.less_than_equals_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::AppendByteString => ExBudget {
mem: self
.append_byte_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.append_byte_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::ConsByteString => ExBudget {
mem: self
.cons_byte_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.cons_byte_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::SliceByteString => ExBudget {
mem: self.slice_byte_string.mem.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
cpu: self.slice_byte_string.cpu.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
},
DefaultFunction::LengthOfByteString => ExBudget {
mem: self.length_of_byte_string.mem.cost(args[0].to_ex_mem()),
cpu: self.length_of_byte_string.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::IndexByteString => ExBudget {
mem: self
.index_byte_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.index_byte_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::EqualsByteString => ExBudget {
mem: self
.equals_byte_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.equals_byte_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::LessThanByteString => ExBudget {
mem: self
.less_than_byte_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.less_than_byte_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::LessThanEqualsByteString => ExBudget {
mem: self
.less_than_equals_byte_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.less_than_equals_byte_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::Sha2_256 => ExBudget {
mem: self.sha2_256.mem.cost(args[0].to_ex_mem()),
cpu: self.sha2_256.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::Sha3_256 => ExBudget {
mem: self.sha3_256.mem.cost(args[0].to_ex_mem()),
cpu: self.sha3_256.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::Blake2b_256 => ExBudget {
mem: self.blake2b_256.mem.cost(args[0].to_ex_mem()),
cpu: self.blake2b_256.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::VerifyEd25519Signature => ExBudget {
mem: self.verify_ed25519_signature.mem.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
cpu: self.verify_ed25519_signature.cpu.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
},
DefaultFunction::VerifyEcdsaSecp256k1Signature => unreachable!(),
DefaultFunction::VerifySchnorrSecp256k1Signature => unreachable!(),
DefaultFunction::AppendString => ExBudget {
mem: self
.append_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.append_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::EqualsString => ExBudget {
mem: self
.equals_string
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.equals_string
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::EncodeUtf8 => ExBudget {
mem: self.encode_utf8.mem.cost(args[0].to_ex_mem()),
cpu: self.encode_utf8.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::DecodeUtf8 => ExBudget {
mem: self.decode_utf8.mem.cost(args[0].to_ex_mem()),
cpu: self.decode_utf8.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::IfThenElse => ExBudget {
mem: self.if_then_else.mem.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
cpu: self.if_then_else.cpu.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
},
DefaultFunction::ChooseUnit => ExBudget {
mem: self
.choose_unit
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.choose_unit
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::Trace => ExBudget {
mem: self
.trace
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.trace
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::FstPair => ExBudget {
mem: self.fst_pair.mem.cost(args[0].to_ex_mem()),
cpu: self.fst_pair.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::SndPair => ExBudget {
mem: self.snd_pair.mem.cost(args[0].to_ex_mem()),
cpu: self.snd_pair.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::ChooseList => ExBudget {
mem: self.choose_list.mem.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
cpu: self.choose_list.cpu.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
),
},
DefaultFunction::MkCons => ExBudget {
mem: self
.mk_cons
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.mk_cons
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::HeadList => ExBudget {
mem: self.head_list.mem.cost(args[0].to_ex_mem()),
cpu: self.head_list.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::TailList => ExBudget {
mem: self.tail_list.mem.cost(args[0].to_ex_mem()),
cpu: self.tail_list.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::NullList => ExBudget {
mem: self.null_list.mem.cost(args[0].to_ex_mem()),
cpu: self.null_list.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::ChooseData => ExBudget {
mem: self.choose_data.mem.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
args[3].to_ex_mem(),
args[4].to_ex_mem(),
args[5].to_ex_mem(),
),
cpu: self.choose_data.cpu.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
args[2].to_ex_mem(),
args[3].to_ex_mem(),
args[4].to_ex_mem(),
args[5].to_ex_mem(),
),
},
DefaultFunction::ConstrData => ExBudget {
mem: self
.constr_data
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.constr_data
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::MapData => ExBudget {
mem: self.map_data.mem.cost(args[0].to_ex_mem()),
cpu: self.map_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::ListData => ExBudget {
mem: self.list_data.mem.cost(args[0].to_ex_mem()),
cpu: self.list_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::IData => ExBudget {
mem: self.i_data.mem.cost(args[0].to_ex_mem()),
cpu: self.i_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::BData => ExBudget {
mem: self.b_data.mem.cost(args[0].to_ex_mem()),
cpu: self.b_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::UnConstrData => ExBudget {
mem: self.un_constr_data.mem.cost(args[0].to_ex_mem()),
cpu: self.un_constr_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::UnMapData => ExBudget {
mem: self.un_map_data.mem.cost(args[0].to_ex_mem()),
cpu: self.un_map_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::UnListData => ExBudget {
mem: self.un_list_data.mem.cost(args[0].to_ex_mem()),
cpu: self.un_list_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::UnIData => ExBudget {
mem: self.un_i_data.mem.cost(args[0].to_ex_mem()),
cpu: self.un_i_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::UnBData => ExBudget {
mem: self.un_b_data.mem.cost(args[0].to_ex_mem()),
cpu: self.un_b_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::EqualsData => ExBudget {
mem: self
.equals_data
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.equals_data
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::SerialiseData => unreachable!(),
DefaultFunction::MkPairData => ExBudget {
mem: self
.mk_pair_data
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.mk_pair_data
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::MkNilData => ExBudget {
mem: self.mk_nil_data.mem.cost(args[0].to_ex_mem()),
cpu: self.mk_nil_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::MkNilPairData => ExBudget {
mem: self.mk_nil_pair_data.mem.cost(args[0].to_ex_mem()),
cpu: self.mk_nil_pair_data.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::Keccak_256 => todo!(),
DefaultFunction::Blake2b_224 => todo!(),
DefaultFunction::Bls12_381_G1_Add => todo!(),
DefaultFunction::Bls12_381_G1_Neg => todo!(),
DefaultFunction::Bls12_381_G1_Scalarmul => todo!(),
DefaultFunction::Bls12_381_G1_Equal => todo!(),
DefaultFunction::Bls12_381_G1_Compress => todo!(),
DefaultFunction::Bls12_381_G1_Uncompress => todo!(),
DefaultFunction::Bls12_381_G1_Hashtogroup => todo!(),
DefaultFunction::Bls12_381_G2_Add => todo!(),
DefaultFunction::Bls12_381_G2_Neg => todo!(),
DefaultFunction::Bls12_381_G2_Scalarmul => todo!(),
DefaultFunction::Bls12_381_G2_Equal => todo!(),
DefaultFunction::Bls12_381_G2_Compress => todo!(),
DefaultFunction::Bls12_381_G2_Uncompress => todo!(),
DefaultFunction::Bls12_381_G2_Hashtogroup => todo!(),
DefaultFunction::Bls12_381_MillerLoop => todo!(),
DefaultFunction::Bls12_381_MulMlResult => todo!(),
DefaultFunction::Bls12_381_FinalVerify => todo!(),
}
}
} }
pub fn initialize_cost_model(version: &Language, costs: &[i64]) -> CostModel { pub fn initialize_cost_model(version: &Language, costs: &[i64]) -> CostModel {
@ -3105,6 +2811,25 @@ pub fn initialize_cost_model(version: &Language, costs: &[i64]) -> CostModel {
.unwrap_or(&30000000000), .unwrap_or(&30000000000),
}), }),
}, },
blake2b_224: todo!(),
keccak_256: todo!(),
bls12_381_g1_add: todo!(),
bls12_381_g1_neg: todo!(),
bls12_381_g1_scalarmul: todo!(),
bls12_381_g1_equal: todo!(),
bls12_381_g1_compress: todo!(),
bls12_381_g1_uncompress: todo!(),
bls12_381_g1_hashtogroup: todo!(),
bls12_381_g2_add: todo!(),
bls12_381_g2_neg: todo!(),
bls12_381_g2_scalarmul: todo!(),
bls12_381_g2_equal: todo!(),
bls12_381_g2_compress: todo!(),
bls12_381_g2_uncompress: todo!(),
bls12_381_g2_hashtogroup: todo!(),
bls12_381_millerloop: todo!(),
bls12_381_mulmlresult: todo!(),
bls12_381_finalverify: todo!(),
}, },
} }
} }

View File

@ -40,6 +40,8 @@ pub enum Error {
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)]
ByteStringOutOfBounds(BigInt, Vec<u8>), ByteStringOutOfBounds(BigInt, Vec<u8>),
#[error("Attempt to consByteString something bigger than one byte {0}")]
ByteStringConsBiggerThanOneByte(BigInt),
#[error("Divide By Zero\n\n{0} / {1}")] #[error("Divide By Zero\n\n{0} / {1}")]
DivideByZero(BigInt, BigInt), DivideByZero(BigInt, BigInt),
#[error("Ed25519S PublicKey should be 32 bytes but it was {0}")] #[error("Ed25519S PublicKey should be 32 bytes but it was {0}")]
@ -50,7 +52,7 @@ pub enum Error {
DeserialisationError(String, Value), DeserialisationError(String, Value),
#[error("Integer overflow")] #[error("Integer overflow")]
OverflowError, OverflowError,
#[error("blst")] #[error("blst error {0:?}")]
Blst(blst::BLST_ERROR), Blst(blst::BLST_ERROR),
#[error("blst::hashToGroup")] #[error("blst::hashToGroup")]
HashToCurveDstTooBig, HashToCurveDstTooBig,

View File

@ -3,7 +3,7 @@ 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 once_cell::sync::Lazy; use once_cell::sync::Lazy;
use pallas_primitives::babbage::{Constr, PlutusData}; use pallas_primitives::babbage::{Constr, Language, PlutusData};
use crate::{ use crate::{
ast::{Constant, Type}, ast::{Constant, Type},
@ -38,6 +38,20 @@ const BLST_P2_COMPRESSED_SIZE: usize = 96;
// Deferred, // Deferred,
//} //}
pub enum BuiltinSemantics {
V1,
V2,
}
impl From<&Language> for BuiltinSemantics {
fn from(language: &Language) -> Self {
match language {
Language::PlutusV1 => BuiltinSemantics::V1,
Language::PlutusV2 => BuiltinSemantics::V1,
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BuiltinRuntime { pub struct BuiltinRuntime {
pub(super) args: Vec<Value>, pub(super) args: Vec<Value>,
@ -70,8 +84,8 @@ impl BuiltinRuntime {
self.forces += 1; self.forces += 1;
} }
pub fn call(&self, logs: &mut Vec<String>) -> Result<Value, Error> { pub fn call(&self, language: &Language, logs: &mut Vec<String>) -> Result<Value, Error> {
self.fun.call(&self.args, logs) self.fun.call(language.into(), &self.args, logs)
} }
pub fn push(&mut self, arg: Value) -> Result<(), Error> { pub fn push(&mut self, arg: Value) -> Result<(), Error> {
@ -82,12 +96,8 @@ impl BuiltinRuntime {
Ok(()) Ok(())
} }
pub fn to_ex_budget_v2(&self, costs: &BuiltinCosts) -> ExBudget { pub fn to_ex_budget(&self, costs: &BuiltinCosts) -> ExBudget {
costs.to_ex_budget_v2(self.fun, &self.args) costs.to_ex_budget(self.fun, &self.args)
}
pub fn to_ex_budget_v1(&self, costs: &BuiltinCosts) -> ExBudget {
costs.to_ex_budget_v1(self.fun, &self.args)
} }
} }
@ -419,7 +429,12 @@ impl DefaultFunction {
// This should be safe because we've already checked // This should be safe because we've already checked
// the types of the args as they were pushed. Although // the types of the args as they were pushed. Although
// the unreachables look ugly, it's the reality of the situation. // the unreachables look ugly, it's the reality of the situation.
pub fn call(&self, args: &[Value], logs: &mut Vec<String>) -> Result<Value, Error> { pub fn call(
&self,
semantics: BuiltinSemantics,
args: &[Value],
logs: &mut Vec<String>,
) -> Result<Value, Error> {
match self { match self {
DefaultFunction::AddInteger => { DefaultFunction::AddInteger => {
let arg1 = args[0].unwrap_integer(); let arg1 = args[0].unwrap_integer();
@ -545,9 +560,20 @@ impl DefaultFunction {
let arg1 = args[0].unwrap_integer(); let arg1 = args[0].unwrap_integer();
let arg2 = args[1].unwrap_byte_string(); let arg2 = args[1].unwrap_byte_string();
let byte: u8 = match semantics {
BuiltinSemantics::V1 => {
let wrap = arg1.mod_floor(&256.into()); let wrap = arg1.mod_floor(&256.into());
let byte: u8 = wrap.try_into().unwrap(); wrap.try_into().unwrap()
}
BuiltinSemantics::V2 => {
if *arg1 > 255.into() {
return Err(Error::ByteStringConsBiggerThanOneByte(arg1.clone()));
}
arg1.try_into().unwrap()
}
};
let mut ret = vec![byte]; let mut ret = vec![byte];
@ -1261,29 +1287,7 @@ impl DefaultFunction {
DefaultFunction::Bls12_381_G1_Uncompress => { DefaultFunction::Bls12_381_G1_Uncompress => {
let arg1 = args[0].unwrap_byte_string(); let arg1 = args[0].unwrap_byte_string();
if arg1.len() != BLST_P1_COMPRESSED_SIZE { let out = blst::blst_p1::uncompress(arg1)?;
return Err(Error::Blst(blst::BLST_ERROR::BLST_BAD_ENCODING));
}
let mut affine = blst::blst_p1_affine::default();
let mut out = blst::blst_p1::default();
unsafe {
let err = blst::blst_p1_uncompress(&mut affine as *mut _, arg1.as_ptr());
if err != blst::BLST_ERROR::BLST_SUCCESS {
return Err(Error::Blst(err));
}
blst::blst_p1_from_affine(&mut out as *mut _, &affine);
let in_group = blst::blst_p1_in_g1(&out);
if !in_group {
return Err(Error::Blst(blst::BLST_ERROR::BLST_POINT_NOT_IN_GROUP));
}
};
let constant = Constant::Bls12_381G1Element(out.into()); let constant = Constant::Bls12_381G1Element(out.into());
@ -1414,29 +1418,7 @@ impl DefaultFunction {
DefaultFunction::Bls12_381_G2_Uncompress => { DefaultFunction::Bls12_381_G2_Uncompress => {
let arg1 = args[0].unwrap_byte_string(); let arg1 = args[0].unwrap_byte_string();
if arg1.len() != BLST_P2_COMPRESSED_SIZE { let out = blst::blst_p2::uncompress(arg1)?;
return Err(Error::Blst(blst::BLST_ERROR::BLST_BAD_ENCODING));
}
let mut affine = blst::blst_p2_affine::default();
let mut out = blst::blst_p2::default();
unsafe {
let err = blst::blst_p2_uncompress(&mut affine as *mut _, arg1.as_ptr());
if err != blst::BLST_ERROR::BLST_SUCCESS {
return Err(Error::Blst(err));
}
blst::blst_p2_from_affine(&mut out as *mut _, &affine);
let in_group = blst::blst_p2_in_g2(&out);
if !in_group {
return Err(Error::Blst(blst::BLST_ERROR::BLST_POINT_NOT_IN_GROUP));
}
};
let constant = Constant::Bls12_381G2Element(out.into()); let constant = Constant::Bls12_381G2Element(out.into());
@ -1519,6 +1501,10 @@ impl DefaultFunction {
pub trait Compressable { pub trait Compressable {
fn compress(&self) -> Vec<u8>; fn compress(&self) -> Vec<u8>;
fn uncompress(bytes: &[u8]) -> Result<Self, Error>
where
Self: std::marker::Sized;
} }
impl Compressable for blst::blst_p1 { impl Compressable for blst::blst_p1 {
@ -1531,6 +1517,34 @@ impl Compressable for blst::blst_p1 {
out.to_vec() out.to_vec()
} }
fn uncompress(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() != BLST_P1_COMPRESSED_SIZE {
return Err(Error::Blst(blst::BLST_ERROR::BLST_BAD_ENCODING));
}
let mut affine = blst::blst_p1_affine::default();
let mut out = blst::blst_p1::default();
unsafe {
let err = blst::blst_p1_uncompress(&mut affine as *mut _, bytes.as_ptr());
if err != blst::BLST_ERROR::BLST_SUCCESS {
return Err(Error::Blst(err));
}
blst::blst_p1_from_affine(&mut out as *mut _, &affine);
let in_group = blst::blst_p1_in_g1(&out);
if !in_group {
return Err(Error::Blst(blst::BLST_ERROR::BLST_POINT_NOT_IN_GROUP));
}
};
Ok(out)
}
} }
impl Compressable for blst::blst_p2 { impl Compressable for blst::blst_p2 {
@ -1543,6 +1557,34 @@ impl Compressable for blst::blst_p2 {
out.to_vec() out.to_vec()
} }
fn uncompress(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() != BLST_P2_COMPRESSED_SIZE {
return Err(Error::Blst(blst::BLST_ERROR::BLST_BAD_ENCODING));
}
let mut affine = blst::blst_p2_affine::default();
let mut out = blst::blst_p2::default();
unsafe {
let err = blst::blst_p2_uncompress(&mut affine as *mut _, bytes.as_ptr());
if err != blst::BLST_ERROR::BLST_SUCCESS {
return Err(Error::Blst(err));
}
blst::blst_p2_from_affine(&mut out as *mut _, &affine);
let in_group = blst::blst_p2_in_g2(&out);
if !in_group {
return Err(Error::Blst(blst::BLST_ERROR::BLST_POINT_NOT_IN_GROUP));
}
};
Ok(out)
}
} }
pub fn convert_tag_to_constr(tag: u64) -> Option<u64> { pub fn convert_tag_to_constr(tag: u64) -> Option<u64> {