diff --git a/Cargo.lock b/Cargo.lock index ad5aedf6..23eb8c71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,6 +368,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blst" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "bstr" version = "1.4.0" @@ -1048,6 +1060,12 @@ dependencies = [ "url", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.10" @@ -1693,9 +1711,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -2744,6 +2762,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.20" @@ -2982,6 +3009,7 @@ name = "uplc" version = "1.0.20-alpha" dependencies = [ "anyhow", + "blst", "cryptoxide", "flat-rs", "hex", @@ -2993,6 +3021,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", + "once_cell", "pallas-addresses", "pallas-codec", "pallas-crypto", @@ -3399,6 +3428,20 @@ name = "zeroize" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] [[package]] name = "zip" diff --git a/crates/aiken-lang/src/builtins.rs b/crates/aiken-lang/src/builtins.rs index 6c1fbdc6..bafd854a 100644 --- a/crates/aiken-lang/src/builtins.rs +++ b/crates/aiken-lang/src/builtins.rs @@ -452,7 +452,11 @@ pub fn from_default_function( Some((tipo, 2)) } - DefaultFunction::Sha2_256 | DefaultFunction::Sha3_256 | DefaultFunction::Blake2b_256 => { + DefaultFunction::Sha2_256 + | DefaultFunction::Sha3_256 + | DefaultFunction::Blake2b_224 + | DefaultFunction::Blake2b_256 + | DefaultFunction::Keccak_256 => { let tipo = function(vec![byte_array()], byte_array()); Some((tipo, 1)) @@ -643,6 +647,24 @@ pub fn from_default_function( let tipo = function(vec![a.clone(), list(a.clone())], list(a)); Some((tipo, 2)) } + + 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!(), }; info.map(|(tipo, arity)| { diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index d3fea47f..ed4e8a28 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -1292,6 +1292,9 @@ pub fn convert_constants_to_data(constants: Vec>) -> Vec todo!(), + UplcConstant::Bls12_381G2Element(_) => todo!(), + UplcConstant::Bls12_381MlResult(_) => todo!(), }; new_constants.push(constant); } diff --git a/crates/uplc/Cargo.toml b/crates/uplc/Cargo.toml index 5c7d4361..da1891bd 100644 --- a/crates/uplc/Cargo.toml +++ b/crates/uplc/Cargo.toml @@ -34,6 +34,8 @@ strum = "0.24.1" strum_macros = "0.24.3" thiserror = "1.0.39" flat-rs = { path = "../flat-rs", version = "1.0.20-alpha" } +blst = "0.3.11" +once_cell = "1.18.0" [target.'cfg(not(target_family="wasm"))'.dependencies] secp256k1 = { version = "0.26.0" } diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index a4647ab5..6965c7ff 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -261,6 +261,9 @@ pub enum Constant { // Apply(Box, Type), // tag: 8 Data(PlutusData), + Bls12_381G1Element(Box), + Bls12_381G2Element(Box), + Bls12_381MlResult(Box), } pub struct Data {} @@ -335,6 +338,9 @@ pub enum Type { List(Rc), Pair(Rc, Rc), Data, + Bls12_381G1Element, + Bls12_381G2Element, + Bls12_381MlResult, } impl Display for Type { @@ -348,6 +354,9 @@ impl Display for Type { Type::List(t) => write!(f, "list {t}"), Type::Pair(t1, t2) => write!(f, "pair {t1} {t2}"), Type::Data => write!(f, "data"), + Type::Bls12_381G1Element => write!(f, "bls12_381_G1_element"), + Type::Bls12_381G2Element => write!(f, "bls12_381_G2_element"), + Type::Bls12_381MlResult => write!(f, "bls12_381_mlresult"), } } } diff --git a/crates/uplc/src/builtins.rs b/crates/uplc/src/builtins.rs index d583b010..336af60f 100644 --- a/crates/uplc/src/builtins.rs +++ b/crates/uplc/src/builtins.rs @@ -35,6 +35,8 @@ pub enum DefaultFunction { Sha2_256 = 18, Sha3_256 = 19, Blake2b_256 = 20, + Keccak_256 = 71, + Blake2b_224 = 72, VerifyEd25519Signature = 21, VerifyEcdsaSecp256k1Signature = 52, VerifySchnorrSecp256k1Signature = 53, @@ -82,6 +84,25 @@ pub enum DefaultFunction { MkPairData = 48, MkNilData = 49, MkNilPairData = 50, + + // BLS Builtins + Bls12_381_G1_Add = 54, + Bls12_381_G1_Neg = 55, + Bls12_381_G1_Scalarmul = 56, + Bls12_381_G1_Equal = 57, + Bls12_381_G1_Compress = 58, + Bls12_381_G1_Uncompress = 59, + Bls12_381_G1_Hashtogroup = 60, + Bls12_381_G2_Add = 61, + Bls12_381_G2_Neg = 62, + Bls12_381_G2_Scalarmul = 63, + Bls12_381_G2_Equal = 64, + Bls12_381_G2_Compress = 65, + Bls12_381_G2_Uncompress = 66, + Bls12_381_G2_Hashtogroup = 67, + Bls12_381_MillerLoop = 68, + Bls12_381_MulMlResult = 69, + Bls12_381_FinalVerify = 70, } impl TryFrom for DefaultFunction { @@ -138,6 +159,7 @@ impl TryFrom for DefaultFunction { v if v == DefaultFunction::Sha2_256 as u8 => Ok(DefaultFunction::Sha2_256), v if v == DefaultFunction::Sha3_256 as u8 => Ok(DefaultFunction::Sha3_256), v if v == DefaultFunction::Blake2b_256 as u8 => Ok(DefaultFunction::Blake2b_256), + v if v == DefaultFunction::Blake2b_224 as u8 => Ok(DefaultFunction::Blake2b_224), v if v == DefaultFunction::VerifyEd25519Signature as u8 => { Ok(DefaultFunction::VerifyEd25519Signature) } @@ -191,6 +213,58 @@ impl TryFrom for DefaultFunction { v if v == DefaultFunction::MkPairData as u8 => Ok(DefaultFunction::MkPairData), v if v == DefaultFunction::MkNilData as u8 => Ok(DefaultFunction::MkNilData), v if v == DefaultFunction::MkNilPairData as u8 => Ok(DefaultFunction::MkNilPairData), + v if v == DefaultFunction::Bls12_381_G1_Add as u8 => { + Ok(DefaultFunction::Bls12_381_G1_Add) + } + v if v == DefaultFunction::Bls12_381_G1_Neg as u8 => { + Ok(DefaultFunction::Bls12_381_G1_Neg) + } + v if v == DefaultFunction::Bls12_381_G1_Scalarmul as u8 => { + Ok(DefaultFunction::Bls12_381_G1_Scalarmul) + } + v if v == DefaultFunction::Bls12_381_G1_Equal as u8 => { + Ok(DefaultFunction::Bls12_381_G1_Equal) + } + v if v == DefaultFunction::Bls12_381_G1_Compress as u8 => { + Ok(DefaultFunction::Bls12_381_G1_Compress) + } + v if v == DefaultFunction::Bls12_381_G1_Uncompress as u8 => { + Ok(DefaultFunction::Bls12_381_G1_Uncompress) + } + v if v == DefaultFunction::Bls12_381_G1_Hashtogroup as u8 => { + Ok(DefaultFunction::Bls12_381_G1_Hashtogroup) + } + v if v == DefaultFunction::Bls12_381_G2_Add as u8 => { + Ok(DefaultFunction::Bls12_381_G2_Add) + } + v if v == DefaultFunction::Bls12_381_G2_Neg as u8 => { + Ok(DefaultFunction::Bls12_381_G2_Neg) + } + v if v == DefaultFunction::Bls12_381_G2_Scalarmul as u8 => { + Ok(DefaultFunction::Bls12_381_G2_Scalarmul) + } + v if v == DefaultFunction::Bls12_381_G2_Equal as u8 => { + Ok(DefaultFunction::Bls12_381_G2_Equal) + } + v if v == DefaultFunction::Bls12_381_G2_Compress as u8 => { + Ok(DefaultFunction::Bls12_381_G2_Compress) + } + v if v == DefaultFunction::Bls12_381_G2_Uncompress as u8 => { + Ok(DefaultFunction::Bls12_381_G2_Uncompress) + } + v if v == DefaultFunction::Bls12_381_G2_Hashtogroup as u8 => { + Ok(DefaultFunction::Bls12_381_G2_Hashtogroup) + } + v if v == DefaultFunction::Bls12_381_MillerLoop as u8 => { + Ok(DefaultFunction::Bls12_381_MillerLoop) + } + v if v == DefaultFunction::Bls12_381_MulMlResult as u8 => { + Ok(DefaultFunction::Bls12_381_MulMlResult) + } + v if v == DefaultFunction::Bls12_381_FinalVerify as u8 => { + Ok(DefaultFunction::Bls12_381_FinalVerify) + } + _ => Err(de::Error::Message(format!( "Default Function not found - {v}" ))), @@ -226,6 +300,8 @@ impl FromStr for DefaultFunction { "sha2_256" => Ok(Sha2_256), "sha3_256" => Ok(Sha3_256), "blake2b_256" => Ok(Blake2b_256), + "keccak_256" => Ok(Keccak_256), + "blake2b_224" => Ok(Blake2b_224), "verifyEd25519Signature" => Ok(VerifyEd25519Signature), "verifyEcdsaSecp256k1Signature" => Ok(VerifyEcdsaSecp256k1Signature), "verifySchnorrSecp256k1Signature" => Ok(VerifySchnorrSecp256k1Signature), @@ -259,6 +335,23 @@ impl FromStr for DefaultFunction { "mkPairData" => Ok(MkPairData), "mkNilData" => Ok(MkNilData), "mkNilPairData" => Ok(MkNilPairData), + "bls12_381_g1_add" => Ok(Bls12_381_G1_Add), + "bls12_381_g1_neg" => Ok(Bls12_381_G1_Neg), + "bls12_381_g1_scalarmul" => Ok(Bls12_381_G1_Scalarmul), + "bls12_381_g1_equal" => Ok(Bls12_381_G1_Equal), + "bls12_381_g1_compress" => Ok(Bls12_381_G1_Compress), + "bls12_381_g1_uncompress" => Ok(Bls12_381_G1_Uncompress), + "bls12_381_g1_hashtogroup" => Ok(Bls12_381_G1_Hashtogroup), + "bls12_381_g2_add" => Ok(Bls12_381_G2_Add), + "bls12_381_g2_neg" => Ok(Bls12_381_G2_Neg), + "bls12_381_g2_scalarmul" => Ok(Bls12_381_G2_Scalarmul), + "bls12_381_g2_equal" => Ok(Bls12_381_G2_Equal), + "bls12_381_g2_compress" => Ok(Bls12_381_G2_Compress), + "bls12_381_g2_uncompress" => Ok(Bls12_381_G2_Uncompress), + "bls12_381_g2_hashtogroup" => Ok(Bls12_381_G2_Hashtogroup), + "bls12_381_millerloop" => Ok(Bls12_381_MillerLoop), + "bls12_381_mulmlresult" => Ok(Bls12_381_MulMlResult), + "bls12_381_finalverify" => Ok(Bls12_381_FinalVerify), rest => Err(format!("Default Function not found - {rest}")), } } @@ -290,6 +383,8 @@ impl Display for DefaultFunction { Sha2_256 => write!(f, "sha2_256"), Sha3_256 => write!(f, "sha3_256"), Blake2b_256 => write!(f, "blake2b_256"), + Keccak_256 => write!(f, "keccak_256"), + Blake2b_224 => write!(f, "blake2b_224"), VerifyEd25519Signature => write!(f, "verifySignature"), VerifyEcdsaSecp256k1Signature => write!(f, "verifyEcdsaSecp256k1Signature"), VerifySchnorrSecp256k1Signature => write!(f, "verifySchnorrSecp256k1Signature"), @@ -323,6 +418,23 @@ impl Display for DefaultFunction { MkPairData => write!(f, "mkPairData"), MkNilData => write!(f, "mkNilData"), MkNilPairData => write!(f, "mkNilPairData"), + Bls12_381_G1_Add => write!(f, "bls12_381_g1_add"), + Bls12_381_G1_Neg => write!(f, "bls12_381_g1_neg"), + Bls12_381_G1_Scalarmul => write!(f, "bls12_381_g1_scalarmul"), + Bls12_381_G1_Equal => write!(f, "bls12_381_g1_equal"), + Bls12_381_G1_Compress => write!(f, "bls12_381_g1_compress"), + Bls12_381_G1_Uncompress => write!(f, "bls12_381_g1_uncompress"), + Bls12_381_G1_Hashtogroup => write!(f, "bls12_381_g1_hashtogroup"), + Bls12_381_G2_Add => write!(f, "bls12_381_g2_add"), + Bls12_381_G2_Neg => write!(f, "bls12_381_g2_neg"), + Bls12_381_G2_Scalarmul => write!(f, "bls12_381_g2_scalarmul"), + Bls12_381_G2_Equal => write!(f, "bls12_381_g2_equal"), + Bls12_381_G2_Compress => write!(f, "bls12_381_g2_compress"), + Bls12_381_G2_Uncompress => write!(f, "bls12_381_g2_uncompress"), + Bls12_381_G2_Hashtogroup => write!(f, "bls12_381_g2_hashtogroup"), + Bls12_381_MillerLoop => write!(f, "bls12_381_millerloop"), + Bls12_381_MulMlResult => write!(f, "bls12_381_mulmlresult"), + Bls12_381_FinalVerify => write!(f, "bls12_381_finalverify"), } } } @@ -352,7 +464,9 @@ impl DefaultFunction { LessThanEqualsByteString => "less_than_equals_bytearray", Sha2_256 => "sha2_256", Sha3_256 => "sha3_256", + Blake2b_224 => "blake2b_224", Blake2b_256 => "blake2b_256", + Keccak_256 => "keccak_256", VerifyEd25519Signature => "verify_ed25519_signature", VerifyEcdsaSecp256k1Signature => "verify_ecdsa_secp256k1_signature", VerifySchnorrSecp256k1Signature => "verify_schnorr_secp256k1_signature", @@ -386,6 +500,23 @@ impl DefaultFunction { MkPairData => "mk_pair_data", MkNilData => "mk_nil_data", MkNilPairData => "mk_nil_pair_data", + Bls12_381_G1_Add => "bls12_381_g1_add", + Bls12_381_G1_Neg => "bls12_381_g1_neg", + Bls12_381_G1_Scalarmul => "bls12_381_g1_scalarmul", + Bls12_381_G1_Equal => "bls12_381_g1_equal", + Bls12_381_G1_Compress => "bls12_381_g1_compress", + Bls12_381_G1_Uncompress => "bls12_381_g1_uncompress", + Bls12_381_G1_Hashtogroup => "bls12_381_g1_hashtogroup", + Bls12_381_G2_Add => "bls12_381_g2_add", + Bls12_381_G2_Neg => "bls12_381_g2_neg", + Bls12_381_G2_Scalarmul => "bls12_381_g2_scalarmul", + Bls12_381_G2_Equal => "bls12_381_g2_equal", + Bls12_381_G2_Compress => "bls12_381_g2_compress", + Bls12_381_G2_Uncompress => "bls12_381_g2_uncompress", + Bls12_381_G2_Hashtogroup => "bls12_381_g2_hashtogroup", + Bls12_381_MillerLoop => "bls12_381_millerloop", + Bls12_381_MulMlResult => "bls12_381_mulmlresult", + Bls12_381_FinalVerify => "bls12_381_finalverify", } .to_string() } diff --git a/crates/uplc/src/flat.rs b/crates/uplc/src/flat.rs index 3b36b516..3c59388c 100644 --- a/crates/uplc/src/flat.rs +++ b/crates/uplc/src/flat.rs @@ -487,6 +487,9 @@ impl Encode for Constant { cbor.encode(e)?; } + Constant::Bls12_381G1Element(_) => todo!(), + Constant::Bls12_381G2Element(_) => todo!(), + Constant::Bls12_381MlResult(_) => todo!(), } Ok(()) @@ -520,6 +523,9 @@ 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!(), } } @@ -540,6 +546,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!(), } } @@ -619,6 +628,9 @@ fn decode_constant_value(typ: Rc, d: &mut Decoder) -> Result todo!(), + Type::Bls12_381G2Element => todo!(), + Type::Bls12_381MlResult => todo!(), } } diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index 7f9a83f2..6192c42d 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -395,6 +395,9 @@ impl From<&Constant> for Type { Type::Pair(Rc::new(t1.clone()), Rc::new(t2.clone())) } Constant::Data(_) => Type::Data, + Constant::Bls12_381G1Element(_) => Type::Bls12_381G1Element, + Constant::Bls12_381G2Element(_) => Type::Bls12_381G2Element, + Constant::Bls12_381MlResult(_) => Type::Bls12_381MlResult, } } } diff --git a/crates/uplc/src/machine/cost_model.rs b/crates/uplc/src/machine/cost_model.rs index 507a07cc..6ab7f3c2 100644 --- a/crates/uplc/src/machine/cost_model.rs +++ b/crates/uplc/src/machine/cost_model.rs @@ -1428,6 +1428,25 @@ impl BuiltinCosts { 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!(), } } @@ -1830,6 +1849,25 @@ impl BuiltinCosts { 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!(), } } } diff --git a/crates/uplc/src/machine/error.rs b/crates/uplc/src/machine/error.rs index 86dce919..85c07b91 100644 --- a/crates/uplc/src/machine/error.rs +++ b/crates/uplc/src/machine/error.rs @@ -50,6 +50,10 @@ pub enum Error { DeserialisationError(String, Value), #[error("Integer overflow")] OverflowError, + #[error("blst")] + Blst(blst::BLST_ERROR), + #[error("blst::hashToGroup")] + HashToCurveDstTooBig, #[cfg(not(target_family = "wasm"))] #[error(transparent)] Secp256k1(#[from] secp256k1::Error), diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index e8ea3f4c..7092deb8 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -1,6 +1,8 @@ -use std::{ops::Deref, rc::Rc}; +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 crate::{ @@ -15,6 +17,23 @@ use super::{ Error, Value, }; +static SCALAR_PERIOD: Lazy = Lazy::new(|| { + BigInt::from_bytes_be( + num_bigint::Sign::Plus, + &[ + 0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, + 0xd8, 0x05, 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, + ], + ) +}); + +const BLST_P1_COMPRESSED_SIZE: usize = 48; + +const BLST_P2_COMPRESSED_SIZE: usize = 96; + +// 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; + //#[derive(std::cmp::PartialEq)] //pub enum EvalMode { // Immediate, @@ -103,7 +122,9 @@ impl DefaultFunction { DefaultFunction::LessThanEqualsByteString => 2, DefaultFunction::Sha2_256 => 1, DefaultFunction::Sha3_256 => 1, + DefaultFunction::Blake2b_224 => 1, DefaultFunction::Blake2b_256 => 1, + DefaultFunction::Keccak_256 => 1, DefaultFunction::VerifyEd25519Signature => 3, DefaultFunction::VerifyEcdsaSecp256k1Signature => 3, DefaultFunction::VerifySchnorrSecp256k1Signature => 3, @@ -137,6 +158,23 @@ impl DefaultFunction { DefaultFunction::MkPairData => 2, DefaultFunction::MkNilData => 1, DefaultFunction::MkNilPairData => 1, + DefaultFunction::Bls12_381_G1_Add => 2, + DefaultFunction::Bls12_381_G1_Neg => 1, + DefaultFunction::Bls12_381_G1_Scalarmul => 2, + DefaultFunction::Bls12_381_G1_Equal => 2, + DefaultFunction::Bls12_381_G1_Compress => 1, + DefaultFunction::Bls12_381_G1_Uncompress => 1, + DefaultFunction::Bls12_381_G1_Hashtogroup => 2, + DefaultFunction::Bls12_381_G2_Add => 2, + DefaultFunction::Bls12_381_G2_Neg => 1, + DefaultFunction::Bls12_381_G2_Scalarmul => 2, + DefaultFunction::Bls12_381_G2_Equal => 2, + DefaultFunction::Bls12_381_G2_Compress => 1, + DefaultFunction::Bls12_381_G2_Uncompress => 1, + DefaultFunction::Bls12_381_G2_Hashtogroup => 2, + DefaultFunction::Bls12_381_MillerLoop => 2, + DefaultFunction::Bls12_381_MulMlResult => 2, + DefaultFunction::Bls12_381_FinalVerify => 2, } } @@ -162,7 +200,9 @@ impl DefaultFunction { DefaultFunction::LessThanEqualsByteString => 0, DefaultFunction::Sha2_256 => 0, DefaultFunction::Sha3_256 => 0, + DefaultFunction::Blake2b_224 => 0, DefaultFunction::Blake2b_256 => 0, + DefaultFunction::Keccak_256 => 0, DefaultFunction::VerifyEd25519Signature => 0, DefaultFunction::VerifyEcdsaSecp256k1Signature => 0, DefaultFunction::VerifySchnorrSecp256k1Signature => 0, @@ -196,6 +236,23 @@ impl DefaultFunction { DefaultFunction::MkPairData => 0, DefaultFunction::MkNilData => 0, DefaultFunction::MkNilPairData => 0, + DefaultFunction::Bls12_381_G1_Add => 0, + DefaultFunction::Bls12_381_G1_Neg => 0, + DefaultFunction::Bls12_381_G1_Scalarmul => 0, + DefaultFunction::Bls12_381_G1_Equal => 0, + DefaultFunction::Bls12_381_G1_Compress => 0, + DefaultFunction::Bls12_381_G1_Uncompress => 0, + DefaultFunction::Bls12_381_G1_Hashtogroup => 0, + DefaultFunction::Bls12_381_G2_Add => 0, + DefaultFunction::Bls12_381_G2_Neg => 0, + DefaultFunction::Bls12_381_G2_Scalarmul => 0, + DefaultFunction::Bls12_381_G2_Equal => 0, + DefaultFunction::Bls12_381_G2_Compress => 0, + DefaultFunction::Bls12_381_G2_Uncompress => 0, + DefaultFunction::Bls12_381_G2_Hashtogroup => 0, + DefaultFunction::Bls12_381_MillerLoop => 0, + DefaultFunction::Bls12_381_MulMlResult => 0, + DefaultFunction::Bls12_381_FinalVerify => 0, } } @@ -239,7 +296,9 @@ impl DefaultFunction { DefaultFunction::LessThanEqualsByteString => arg.expect_type(Type::ByteString), DefaultFunction::Sha2_256 => arg.expect_type(Type::ByteString), DefaultFunction::Sha3_256 => arg.expect_type(Type::ByteString), + DefaultFunction::Blake2b_224 => arg.expect_type(Type::ByteString), DefaultFunction::Blake2b_256 => arg.expect_type(Type::ByteString), + DefaultFunction::Keccak_256 => arg.expect_type(Type::ByteString), DefaultFunction::VerifyEd25519Signature => arg.expect_type(Type::ByteString), DefaultFunction::VerifyEcdsaSecp256k1Signature => arg.expect_type(Type::ByteString), DefaultFunction::VerifySchnorrSecp256k1Signature => arg.expect_type(Type::ByteString), @@ -320,6 +379,42 @@ impl DefaultFunction { DefaultFunction::MkPairData => arg.expect_type(Type::Data), DefaultFunction::MkNilData => arg.expect_type(Type::Unit), DefaultFunction::MkNilPairData => arg.expect_type(Type::Unit), + + DefaultFunction::Bls12_381_G1_Add => arg.expect_type(Type::Bls12_381G1Element), + DefaultFunction::Bls12_381_G1_Neg => arg.expect_type(Type::Bls12_381G1Element), + DefaultFunction::Bls12_381_G1_Scalarmul => { + if args.is_empty() { + arg.expect_type(Type::Integer) + } else { + arg.expect_type(Type::Bls12_381G1Element) + } + } + DefaultFunction::Bls12_381_G1_Equal => arg.expect_type(Type::Bls12_381G1Element), + DefaultFunction::Bls12_381_G1_Compress => arg.expect_type(Type::Bls12_381G1Element), + DefaultFunction::Bls12_381_G1_Uncompress => arg.expect_type(Type::ByteString), + DefaultFunction::Bls12_381_G1_Hashtogroup => arg.expect_type(Type::ByteString), + DefaultFunction::Bls12_381_G2_Add => arg.expect_type(Type::Bls12_381G2Element), + DefaultFunction::Bls12_381_G2_Neg => arg.expect_type(Type::Bls12_381G2Element), + DefaultFunction::Bls12_381_G2_Scalarmul => { + if args.is_empty() { + arg.expect_type(Type::Integer) + } else { + arg.expect_type(Type::Bls12_381G2Element) + } + } + DefaultFunction::Bls12_381_G2_Equal => arg.expect_type(Type::Bls12_381G2Element), + DefaultFunction::Bls12_381_G2_Compress => arg.expect_type(Type::Bls12_381G2Element), + DefaultFunction::Bls12_381_G2_Uncompress => arg.expect_type(Type::ByteString), + DefaultFunction::Bls12_381_G2_Hashtogroup => arg.expect_type(Type::ByteString), + DefaultFunction::Bls12_381_MillerLoop => { + if args.is_empty() { + arg.expect_type(Type::Bls12_381G1Element) + } else { + arg.expect_type(Type::Bls12_381G2Element) + } + } + DefaultFunction::Bls12_381_MulMlResult => arg.expect_type(Type::Bls12_381MlResult), + DefaultFunction::Bls12_381_FinalVerify => arg.expect_type(Type::Bls12_381MlResult), } } @@ -567,6 +662,22 @@ impl DefaultFunction { Ok(value) } + + DefaultFunction::Blake2b_224 => { + use cryptoxide::{blake2b::Blake2b, digest::Digest}; + + let arg1 = args[0].unwrap_byte_string(); + + let mut digest = [0u8; 28]; + let mut context = Blake2b::new(28); + + context.input(arg1); + context.result(&mut digest); + + let value = Value::byte_string(digest.to_vec()); + + Ok(value) + } DefaultFunction::Blake2b_256 => { use cryptoxide::{blake2b::Blake2b, digest::Digest}; @@ -582,6 +693,23 @@ impl DefaultFunction { Ok(value) } + DefaultFunction::Keccak_256 => { + use cryptoxide::{digest::Digest, sha3::Keccak256}; + + let arg1 = args[0].unwrap_byte_string(); + + let mut hasher = Keccak256::new(); + + hasher.input(arg1); + + let mut bytes = vec![0; hasher.output_bytes()]; + + hasher.result(&mut bytes); + + let value = Value::byte_string(bytes); + + Ok(value) + } DefaultFunction::VerifyEd25519Signature => { use cryptoxide::ed25519; @@ -1036,6 +1164,367 @@ impl DefaultFunction { Ok(value) } + + DefaultFunction::Bls12_381_G1_Add => { + let arg1 = args[0].unwrap_bls12_381_g1_element(); + let arg2 = args[1].unwrap_bls12_381_g1_element(); + + let mut out = blst::blst_p1::default(); + + unsafe { + blst::blst_p1_add_or_double( + &mut out as *mut _, + arg1 as *const _, + arg2 as *const _, + ); + } + + let constant = Constant::Bls12_381G1Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G1_Neg => { + let arg1 = args[0].unwrap_bls12_381_g1_element(); + + let mut out = *arg1; + + unsafe { + blst::blst_p1_cneg( + &mut out as *mut _, + // This was true in the Cardano code + true, + ); + } + + let constant = Constant::Bls12_381G1Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G1_Scalarmul => { + let arg1 = args[0].unwrap_integer(); + let arg2 = args[1].unwrap_bls12_381_g1_element(); + + let size_scalar = size_of::(); + + let arg1 = arg1.mod_floor(&SCALAR_PERIOD); + + let (_, mut arg1) = arg1.to_bytes_be(); + + if size_scalar > arg1.len() { + let diff = size_scalar - arg1.len(); + + let mut new_vec = vec![0; diff]; + + new_vec.append(&mut arg1); + + arg1 = new_vec; + } + + let mut out = blst::blst_p1::default(); + let mut scalar = blst::blst_scalar::default(); + + unsafe { + blst::blst_scalar_from_bendian( + &mut scalar as *mut _, + arg1.as_ptr() as *const _, + ); + + blst::blst_p1_mult( + &mut out as *mut _, + // This was true in the Cardano code + arg2 as *const _, + scalar.b.as_ptr() as *const _, + size_scalar * 8, + ); + } + + let constant = Constant::Bls12_381G1Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G1_Equal => { + let arg1 = args[0].unwrap_bls12_381_g1_element(); + let arg2 = args[1].unwrap_bls12_381_g1_element(); + + let is_equal = unsafe { blst::blst_p1_is_equal(arg1, arg2) }; + + let constant = Constant::Bool(is_equal); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G1_Compress => { + let arg1 = args[0].unwrap_bls12_381_g1_element(); + + let mut out = [0; BLST_P1_COMPRESSED_SIZE]; + + unsafe { + blst::blst_p1_compress(&mut out as *mut _, arg1); + }; + + let constant = Constant::ByteString(out.to_vec()); + + Ok(Value::Con(constant.into())) + } + 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 constant = Constant::Bls12_381G1Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G1_Hashtogroup => { + let arg1 = args[0].unwrap_byte_string(); + let arg2 = args[1].unwrap_byte_string(); + + if arg2.len() > 255 { + return Err(Error::HashToCurveDstTooBig); + } + + let mut out = blst::blst_p1::default(); + let aug = []; + + unsafe { + blst::blst_hash_to_g1( + &mut out as *mut _, + arg1.as_ptr(), + arg1.len(), + arg2.as_ptr(), + arg2.len(), + aug.as_ptr(), + 0, + ); + }; + + let constant = Constant::Bls12_381G1Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G2_Add => { + let arg1 = args[0].unwrap_bls12_381_g2_element(); + let arg2 = args[1].unwrap_bls12_381_g2_element(); + + let mut out = blst::blst_p2::default(); + + unsafe { + blst::blst_p2_add_or_double( + &mut out as *mut _, + arg1 as *const _, + arg2 as *const _, + ); + } + + let constant = Constant::Bls12_381G2Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G2_Neg => { + let arg1 = args[0].unwrap_bls12_381_g2_element(); + + let mut out = *arg1; + + unsafe { + blst::blst_p2_cneg( + &mut out as *mut _, + // This was true in the Cardano code + true, + ); + } + + let constant = Constant::Bls12_381G2Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G2_Scalarmul => { + let arg1 = args[0].unwrap_integer(); + let arg2 = args[1].unwrap_bls12_381_g2_element(); + + let size_scalar = size_of::(); + + let arg1 = arg1.mod_floor(&SCALAR_PERIOD); + + let (_, mut arg1) = arg1.to_bytes_be(); + + if size_scalar > arg1.len() { + let diff = size_scalar - arg1.len(); + + let mut new_vec = vec![0; diff]; + + new_vec.append(&mut arg1); + + arg1 = new_vec; + } + + let mut out = blst::blst_p2::default(); + let mut scalar = blst::blst_scalar::default(); + + unsafe { + blst::blst_scalar_from_bendian( + &mut scalar as *mut _, + arg1.as_ptr() as *const _, + ); + + blst::blst_p2_mult( + &mut out as *mut _, + // This was true in the Cardano code + arg2 as *const _, + scalar.b.as_ptr() as *const _, + size_scalar * 8, + ); + } + + let constant = Constant::Bls12_381G2Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G2_Equal => { + let arg1 = args[0].unwrap_bls12_381_g2_element(); + let arg2 = args[1].unwrap_bls12_381_g2_element(); + + let is_equal = unsafe { blst::blst_p2_is_equal(arg1, arg2) }; + + let constant = Constant::Bool(is_equal); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G2_Compress => { + let arg1 = args[0].unwrap_bls12_381_g2_element(); + + let mut out = [0; BLST_P2_COMPRESSED_SIZE]; + + unsafe { + blst::blst_p2_compress(&mut out as *mut _, arg1); + }; + + let constant = Constant::ByteString(out.to_vec()); + + Ok(Value::Con(constant.into())) + } + 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 constant = Constant::Bls12_381G2Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_G2_Hashtogroup => { + let arg1 = args[0].unwrap_byte_string(); + let arg2 = args[1].unwrap_byte_string(); + + if arg2.len() > 255 { + return Err(Error::HashToCurveDstTooBig); + } + + let mut out = blst::blst_p2::default(); + let aug = []; + + unsafe { + blst::blst_hash_to_g2( + &mut out as *mut _, + arg1.as_ptr(), + arg1.len(), + arg2.as_ptr(), + arg2.len(), + aug.as_ptr(), + 0, + ); + }; + + let constant = Constant::Bls12_381G2Element(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_MillerLoop => { + let arg1 = args[0].unwrap_bls12_381_g1_element(); + let arg2 = args[1].unwrap_bls12_381_g2_element(); + + let mut out = blst::blst_fp12::default(); + + let mut affine1 = blst::blst_p1_affine::default(); + let mut affine2 = blst::blst_p2_affine::default(); + + unsafe { + blst::blst_p1_to_affine(&mut affine1 as *mut _, arg1); + blst::blst_p2_to_affine(&mut affine2 as *mut _, arg2); + + blst::blst_miller_loop(&mut out as *mut _, &affine2, &affine1); + } + + let constant = Constant::Bls12_381MlResult(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_MulMlResult => { + let arg1 = args[0].unwrap_bls12_381_ml_result(); + let arg2 = args[1].unwrap_bls12_381_ml_result(); + + let mut out = blst::blst_fp12::default(); + + unsafe { + blst::blst_fp12_mul(&mut out as *mut _, arg1, arg2); + } + + let constant = Constant::Bls12_381MlResult(out.into()); + + Ok(Value::Con(constant.into())) + } + DefaultFunction::Bls12_381_FinalVerify => { + let arg1 = args[0].unwrap_bls12_381_ml_result(); + let arg2 = args[1].unwrap_bls12_381_ml_result(); + + let verified = unsafe { blst::blst_fp12_finalverify(arg1, arg2) }; + + let constant = Constant::Bool(verified); + + Ok(Value::Con(constant.into())) + } } } } diff --git a/crates/uplc/src/machine/value.rs b/crates/uplc/src/machine/value.rs index 70d6bc8e..f322b0ba 100644 --- a/crates/uplc/src/machine/value.rs +++ b/crates/uplc/src/machine/value.rs @@ -1,4 +1,4 @@ -use std::{collections::VecDeque, ops::Deref, rc::Rc}; +use std::{collections::VecDeque, mem::size_of, ops::Deref, rc::Rc}; use num_bigint::BigInt; use num_traits::Signed; @@ -154,6 +154,42 @@ impl Value { list } + pub(super) fn unwrap_bls12_381_g1_element(&self) -> &blst::blst_p1 { + let Value::Con(inner) = self else { + unreachable!() + }; + + let Constant::Bls12_381G1Element(element) = inner.as_ref() else { + unreachable!() + }; + + element + } + + pub(super) fn unwrap_bls12_381_g2_element(&self) -> &blst::blst_p2 { + let Value::Con(inner) = self else { + unreachable!() + }; + + let Constant::Bls12_381G2Element(element) = inner.as_ref() else { + unreachable!() + }; + + element + } + + pub(super) fn unwrap_bls12_381_ml_result(&self) -> &blst::blst_fp12 { + let Value::Con(inner) = self else { + unreachable!() + }; + + let Constant::Bls12_381MlResult(element) = inner.as_ref() else { + unreachable!() + }; + + element + } + pub fn is_integer(&self) -> bool { matches!(self, Value::Con(i) if matches!(i.as_ref(), Constant::Integer(_))) } @@ -190,6 +226,9 @@ impl Value { Value::Con(l.clone()).to_ex_mem() + Value::Con(r.clone()).to_ex_mem() } Constant::Data(item) => self.data_to_ex_mem(item), + Constant::Bls12_381G1Element(_) => size_of::() as i64 / 8, + Constant::Bls12_381G2Element(_) => size_of::() as i64 / 8, + Constant::Bls12_381MlResult(_) => size_of::() as i64 / 8, }, Value::Delay(_, _) => 1, Value::Lambda { .. } => 1, diff --git a/crates/uplc/src/pretty.rs b/crates/uplc/src/pretty.rs index 9fde6b7d..0848cf58 100644 --- a/crates/uplc/src/pretty.rs +++ b/crates/uplc/src/pretty.rs @@ -256,6 +256,9 @@ impl Constant { .append(RcDoc::text("(")) .append(Self::to_doc_list_plutus_data(d)) .append(RcDoc::text(")")), + Constant::Bls12_381G1Element(_) => todo!(), + Constant::Bls12_381G2Element(_) => todo!(), + Constant::Bls12_381MlResult(_) => todo!(), } } @@ -281,6 +284,9 @@ impl Constant { .append(RcDoc::text(")")), Constant::Data(data) => Self::to_doc_list_plutus_data(data), + Constant::Bls12_381G1Element(_) => todo!(), + Constant::Bls12_381G2Element(_) => todo!(), + Constant::Bls12_381MlResult(_) => todo!(), } } @@ -352,6 +358,9 @@ impl Type { .append(r.to_doc()) .append(")"), Type::Data => RcDoc::text("data"), + Type::Bls12_381G1Element => todo!(), + Type::Bls12_381G2Element => todo!(), + Type::Bls12_381MlResult => todo!(), } } }