diff --git a/crates/uplc/src/flat.rs b/crates/uplc/src/flat.rs index 3c59388c..9bac2f72 100644 --- a/crates/uplc/src/flat.rs +++ b/crates/uplc/src/flat.rs @@ -3,8 +3,11 @@ use crate::{ Constant, DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term, Type, Unique, }, builtins::DefaultFunction, + machine::runtime::Compressable, }; + use anyhow::anyhow; + use flat_rs::{ de::{self, Decode, Decoder}, en::{self, Encode, Encoder}, @@ -487,9 +490,27 @@ impl Encode for Constant { cbor.encode(e)?; } - Constant::Bls12_381G1Element(_) => todo!(), - Constant::Bls12_381G2Element(_) => todo!(), - Constant::Bls12_381MlResult(_) => todo!(), + Constant::Bls12_381G1Element(b) => { + encode_constant(&[9], e)?; + + 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(()) @@ -523,19 +544,29 @@ fn encode_constant_value(x: &Constant, e: &mut Encoder) -> Result<(), en::Error> cbor.encode(e) } - Constant::Bls12_381G1Element(_) => todo!(), - Constant::Bls12_381G2Element(_) => todo!(), - Constant::Bls12_381MlResult(_) => todo!(), + Constant::Bls12_381G1Element(b) => { + let x = b.compress(); + + 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) { match typ { - Type::Bool => bytes.push(4), Type::Integer => bytes.push(0), - Type::String => bytes.push(2), Type::ByteString => bytes.push(1), + Type::String => bytes.push(2), Type::Unit => bytes.push(3), + Type::Bool => bytes.push(4), Type::List(sub_typ) => { bytes.extend(vec![7, 5]); encode_type(sub_typ, bytes); @@ -546,9 +577,9 @@ fn encode_type(typ: &Type, bytes: &mut Vec) { encode_type(type2, bytes); } Type::Data => bytes.push(8), - Type::Bls12_381G1Element => todo!(), - Type::Bls12_381G2Element => todo!(), - Type::Bls12_381MlResult => todo!(), + Type::Bls12_381G1Element => bytes.push(9), + Type::Bls12_381G2Element => bytes.push(10), + Type::Bls12_381MlResult => bytes.push(11), } } @@ -589,6 +620,28 @@ impl<'b> Decode<'b> for Constant { Ok(Constant::Data(data)) } + [9] => { + let p1 = Vec::::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::::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!( "Unknown constant constructor tag: {x:?}" ))), @@ -628,9 +681,25 @@ fn decode_constant_value(typ: Rc, d: &mut Decoder) -> Result todo!(), - Type::Bls12_381G2Element => todo!(), - Type::Bls12_381MlResult => todo!(), + Type::Bls12_381G1Element => { + let p1 = Vec::::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())) + } + Type::Bls12_381G2Element => { + let p2 = Vec::::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) -> Result { Some(1) => Ok(Type::ByteString), Some(3) => Ok(Type::Unit), 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(5) => Ok(Type::List(decode_type(types)?.into())), Some(7) => match types.pop_front() { diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index 6192c42d..6a4d896a 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -315,14 +315,11 @@ impl Machine { } fn eval_builtin_app(&mut self, runtime: BuiltinRuntime) -> Result { - let cost = match self.version { - Language::PlutusV1 => runtime.to_ex_budget_v1(&self.costs.builtin_costs), - Language::PlutusV2 => runtime.to_ex_budget_v2(&self.costs.builtin_costs), - }; + let cost = runtime.to_ex_budget(&self.costs.builtin_costs); 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 { diff --git a/crates/uplc/src/machine/cost_model.rs b/crates/uplc/src/machine/cost_model.rs index 6ab7f3c2..a730d31b 100644 --- a/crates/uplc/src/machine/cost_model.rs +++ b/crates/uplc/src/machine/cost_model.rs @@ -228,7 +228,9 @@ pub struct BuiltinCosts { // Cryptography and hashes pub sha2_256: CostingFun, pub sha3_256: CostingFun, + pub blake2b_224: CostingFun, pub blake2b_256: CostingFun, + pub keccak_256: CostingFun, pub verify_ed25519_signature: CostingFun, pub verify_ecdsa_secp256k1_signature: CostingFun, pub verify_schnorr_secp256k1_signature: CostingFun, @@ -270,6 +272,24 @@ pub struct BuiltinCosts { pub mk_nil_data: CostingFun, pub mk_nil_pair_data: CostingFun, pub serialise_data: CostingFun, + // BLST + bls12_381_g1_add: CostingFun, + bls12_381_g1_neg: CostingFun, + bls12_381_g1_scalarmul: CostingFun, + bls12_381_g1_equal: CostingFun, + bls12_381_g1_compress: CostingFun, + bls12_381_g1_uncompress: CostingFun, + bls12_381_g1_hashtogroup: CostingFun, + bls12_381_g2_add: CostingFun, + bls12_381_g2_neg: CostingFun, + bls12_381_g2_scalarmul: CostingFun, + bls12_381_g2_equal: CostingFun, + bls12_381_g2_compress: CostingFun, + bls12_381_g2_uncompress: CostingFun, + bls12_381_g2_hashtogroup: CostingFun, + bls12_381_millerloop: CostingFun, + bls12_381_mulmlresult: CostingFun, + bls12_381_finalverify: CostingFun, } impl BuiltinCosts { @@ -457,6 +477,16 @@ impl BuiltinCosts { slope: 82523, }), }, + blake2b_224: CostingFun { + mem: OneArgument::LinearCost(LinearSize { + intercept: 30000000000, + slope: 30000000000, + }), + cpu: OneArgument::LinearCost(LinearSize { + intercept: 30000000000, + slope: 30000000000, + }), + }, blake2b_256: CostingFun { mem: OneArgument::ConstantCost(4), cpu: OneArgument::LinearCost(LinearSize { @@ -464,6 +494,16 @@ impl BuiltinCosts { 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 { mem: ThreeArguments::ConstantCost(10), cpu: ThreeArguments::LinearInZ(LinearSize { @@ -633,6 +673,74 @@ impl BuiltinCosts { 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, }), }, + 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 { - 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 { DefaultFunction::AddInteger => ExBudget { mem: self @@ -1449,427 +1576,6 @@ impl BuiltinCosts { 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 { @@ -3105,6 +2811,25 @@ pub fn initialize_cost_model(version: &Language, costs: &[i64]) -> CostModel { .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!(), }, } } diff --git a/crates/uplc/src/machine/error.rs b/crates/uplc/src/machine/error.rs index 85c07b91..468cb518 100644 --- a/crates/uplc/src/machine/error.rs +++ b/crates/uplc/src/machine/error.rs @@ -40,6 +40,8 @@ pub enum Error { Utf8(#[from] FromUtf8Error), #[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)] ByteStringOutOfBounds(BigInt, Vec), + #[error("Attempt to consByteString something bigger than one byte {0}")] + ByteStringConsBiggerThanOneByte(BigInt), #[error("Divide By Zero\n\n{0} / {1}")] DivideByZero(BigInt, BigInt), #[error("Ed25519S PublicKey should be 32 bytes but it was {0}")] @@ -50,7 +52,7 @@ pub enum Error { DeserialisationError(String, Value), #[error("Integer overflow")] OverflowError, - #[error("blst")] + #[error("blst error {0:?}")] Blst(blst::BLST_ERROR), #[error("blst::hashToGroup")] HashToCurveDstTooBig, diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index c654de3a..6e8a59da 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -3,7 +3,7 @@ use std::{mem::size_of, ops::Deref, rc::Rc}; use num_bigint::BigInt; use num_integer::Integer; use once_cell::sync::Lazy; -use pallas_primitives::babbage::{Constr, PlutusData}; +use pallas_primitives::babbage::{Constr, Language, PlutusData}; use crate::{ ast::{Constant, Type}, @@ -38,6 +38,20 @@ const BLST_P2_COMPRESSED_SIZE: usize = 96; // 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)] pub struct BuiltinRuntime { pub(super) args: Vec, @@ -70,8 +84,8 @@ impl BuiltinRuntime { self.forces += 1; } - pub fn call(&self, logs: &mut Vec) -> Result { - self.fun.call(&self.args, logs) + pub fn call(&self, language: &Language, logs: &mut Vec) -> Result { + self.fun.call(language.into(), &self.args, logs) } pub fn push(&mut self, arg: Value) -> Result<(), Error> { @@ -82,12 +96,8 @@ impl BuiltinRuntime { Ok(()) } - pub fn to_ex_budget_v2(&self, costs: &BuiltinCosts) -> ExBudget { - costs.to_ex_budget_v2(self.fun, &self.args) - } - - pub fn to_ex_budget_v1(&self, costs: &BuiltinCosts) -> ExBudget { - costs.to_ex_budget_v1(self.fun, &self.args) + pub fn to_ex_budget(&self, costs: &BuiltinCosts) -> ExBudget { + costs.to_ex_budget(self.fun, &self.args) } } @@ -419,7 +429,12 @@ impl DefaultFunction { // This should be safe because we've already checked // the types of the args as they were pushed. Although // the unreachables look ugly, it's the reality of the situation. - pub fn call(&self, args: &[Value], logs: &mut Vec) -> Result { + pub fn call( + &self, + semantics: BuiltinSemantics, + args: &[Value], + logs: &mut Vec, + ) -> Result { match self { DefaultFunction::AddInteger => { let arg1 = args[0].unwrap_integer(); @@ -545,9 +560,20 @@ impl DefaultFunction { let arg1 = args[0].unwrap_integer(); let arg2 = args[1].unwrap_byte_string(); - let wrap = arg1.mod_floor(&256.into()); + let byte: u8 = match semantics { + BuiltinSemantics::V1 => { + 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]; @@ -1261,29 +1287,7 @@ impl DefaultFunction { DefaultFunction::Bls12_381_G1_Uncompress => { let arg1 = args[0].unwrap_byte_string(); - if arg1.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 _, 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 out = blst::blst_p1::uncompress(arg1)?; let constant = Constant::Bls12_381G1Element(out.into()); @@ -1414,29 +1418,7 @@ impl DefaultFunction { DefaultFunction::Bls12_381_G2_Uncompress => { let arg1 = args[0].unwrap_byte_string(); - if arg1.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 _, 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 out = blst::blst_p2::uncompress(arg1)?; let constant = Constant::Bls12_381G2Element(out.into()); @@ -1519,6 +1501,10 @@ impl DefaultFunction { pub trait Compressable { fn compress(&self) -> Vec; + + fn uncompress(bytes: &[u8]) -> Result + where + Self: std::marker::Sized; } impl Compressable for blst::blst_p1 { @@ -1531,6 +1517,34 @@ impl Compressable for blst::blst_p1 { out.to_vec() } + + fn uncompress(bytes: &[u8]) -> Result { + 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 { @@ -1543,6 +1557,34 @@ impl Compressable for blst::blst_p2 { out.to_vec() } + + fn uncompress(bytes: &[u8]) -> Result { + 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 {