1524 lines
50 KiB
Rust
1524 lines
50 KiB
Rust
use std::{mem::size_of, ops::Deref, rc::Rc};
|
|
|
|
use num_bigint::BigInt;
|
|
use num_integer::Integer;
|
|
use once_cell::sync::Lazy;
|
|
use pallas::ledger::primitives::babbage::{Language, PlutusData};
|
|
|
|
use crate::{
|
|
ast::{Constant, Data, Type},
|
|
builtins::DefaultFunction,
|
|
plutus_data_to_bytes,
|
|
};
|
|
|
|
use super::{
|
|
cost_model::{BuiltinCosts, ExBudget},
|
|
value::{from_pallas_bigint, to_pallas_bigint},
|
|
Error, Value,
|
|
};
|
|
|
|
static SCALAR_PERIOD: Lazy<BigInt> = 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;
|
|
|
|
//#[derive(std::cmp::PartialEq)]
|
|
//pub enum EvalMode {
|
|
// Immediate,
|
|
// 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<Value>,
|
|
fun: DefaultFunction,
|
|
pub(super) forces: u32,
|
|
}
|
|
|
|
impl BuiltinRuntime {
|
|
pub fn new(fun: DefaultFunction) -> BuiltinRuntime {
|
|
Self {
|
|
args: vec![],
|
|
fun,
|
|
forces: 0,
|
|
}
|
|
}
|
|
|
|
pub fn is_arrow(&self) -> bool {
|
|
self.args.len() != self.fun.arity()
|
|
}
|
|
|
|
pub fn is_ready(&self) -> bool {
|
|
self.args.len() == self.fun.arity()
|
|
}
|
|
|
|
pub fn needs_force(&self) -> bool {
|
|
self.forces < self.fun.force_count()
|
|
}
|
|
|
|
pub fn consume_force(&mut self) {
|
|
self.forces += 1;
|
|
}
|
|
|
|
pub fn call(&self, language: &Language, logs: &mut Vec<String>) -> Result<Value, Error> {
|
|
self.fun.call(language.into(), &self.args, logs)
|
|
}
|
|
|
|
pub fn push(&mut self, arg: Value) -> Result<(), Error> {
|
|
self.args.push(arg);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn to_ex_budget(&self, costs: &BuiltinCosts) -> ExBudget {
|
|
costs.to_ex_budget(self.fun, &self.args)
|
|
}
|
|
}
|
|
|
|
impl From<DefaultFunction> for BuiltinRuntime {
|
|
fn from(fun: DefaultFunction) -> Self {
|
|
BuiltinRuntime::new(fun)
|
|
}
|
|
}
|
|
|
|
impl DefaultFunction {
|
|
pub fn arity(&self) -> usize {
|
|
match self {
|
|
DefaultFunction::AddInteger => 2,
|
|
DefaultFunction::SubtractInteger => 2,
|
|
DefaultFunction::MultiplyInteger => 2,
|
|
DefaultFunction::DivideInteger => 2,
|
|
DefaultFunction::QuotientInteger => 2,
|
|
DefaultFunction::RemainderInteger => 2,
|
|
DefaultFunction::ModInteger => 2,
|
|
DefaultFunction::EqualsInteger => 2,
|
|
DefaultFunction::LessThanInteger => 2,
|
|
DefaultFunction::LessThanEqualsInteger => 2,
|
|
DefaultFunction::AppendByteString => 2,
|
|
DefaultFunction::ConsByteString => 2,
|
|
DefaultFunction::SliceByteString => 3,
|
|
DefaultFunction::LengthOfByteString => 1,
|
|
DefaultFunction::IndexByteString => 2,
|
|
DefaultFunction::EqualsByteString => 2,
|
|
DefaultFunction::LessThanByteString => 2,
|
|
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,
|
|
DefaultFunction::AppendString => 2,
|
|
DefaultFunction::EqualsString => 2,
|
|
DefaultFunction::EncodeUtf8 => 1,
|
|
DefaultFunction::DecodeUtf8 => 1,
|
|
DefaultFunction::IfThenElse => 3,
|
|
DefaultFunction::ChooseUnit => 2,
|
|
DefaultFunction::Trace => 2,
|
|
DefaultFunction::FstPair => 1,
|
|
DefaultFunction::SndPair => 1,
|
|
DefaultFunction::ChooseList => 3,
|
|
DefaultFunction::MkCons => 2,
|
|
DefaultFunction::HeadList => 1,
|
|
DefaultFunction::TailList => 1,
|
|
DefaultFunction::NullList => 1,
|
|
DefaultFunction::ChooseData => 6,
|
|
DefaultFunction::ConstrData => 2,
|
|
DefaultFunction::MapData => 1,
|
|
DefaultFunction::ListData => 1,
|
|
DefaultFunction::IData => 1,
|
|
DefaultFunction::BData => 1,
|
|
DefaultFunction::UnConstrData => 1,
|
|
DefaultFunction::UnMapData => 1,
|
|
DefaultFunction::UnListData => 1,
|
|
DefaultFunction::UnIData => 1,
|
|
DefaultFunction::UnBData => 1,
|
|
DefaultFunction::EqualsData => 2,
|
|
DefaultFunction::SerialiseData => 1,
|
|
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,
|
|
}
|
|
}
|
|
|
|
pub fn force_count(&self) -> u32 {
|
|
match self {
|
|
DefaultFunction::AddInteger => 0,
|
|
DefaultFunction::SubtractInteger => 0,
|
|
DefaultFunction::MultiplyInteger => 0,
|
|
DefaultFunction::DivideInteger => 0,
|
|
DefaultFunction::QuotientInteger => 0,
|
|
DefaultFunction::RemainderInteger => 0,
|
|
DefaultFunction::ModInteger => 0,
|
|
DefaultFunction::EqualsInteger => 0,
|
|
DefaultFunction::LessThanInteger => 0,
|
|
DefaultFunction::LessThanEqualsInteger => 0,
|
|
DefaultFunction::AppendByteString => 0,
|
|
DefaultFunction::ConsByteString => 0,
|
|
DefaultFunction::SliceByteString => 0,
|
|
DefaultFunction::LengthOfByteString => 0,
|
|
DefaultFunction::IndexByteString => 0,
|
|
DefaultFunction::EqualsByteString => 0,
|
|
DefaultFunction::LessThanByteString => 0,
|
|
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,
|
|
DefaultFunction::AppendString => 0,
|
|
DefaultFunction::EqualsString => 0,
|
|
DefaultFunction::EncodeUtf8 => 0,
|
|
DefaultFunction::DecodeUtf8 => 0,
|
|
DefaultFunction::IfThenElse => 1,
|
|
DefaultFunction::ChooseUnit => 1,
|
|
DefaultFunction::Trace => 1,
|
|
DefaultFunction::FstPair => 2,
|
|
DefaultFunction::SndPair => 2,
|
|
DefaultFunction::ChooseList => 2,
|
|
DefaultFunction::MkCons => 1,
|
|
DefaultFunction::HeadList => 1,
|
|
DefaultFunction::TailList => 1,
|
|
DefaultFunction::NullList => 1,
|
|
DefaultFunction::ChooseData => 1,
|
|
DefaultFunction::ConstrData => 0,
|
|
DefaultFunction::MapData => 0,
|
|
DefaultFunction::ListData => 0,
|
|
DefaultFunction::IData => 0,
|
|
DefaultFunction::BData => 0,
|
|
DefaultFunction::UnConstrData => 0,
|
|
DefaultFunction::UnMapData => 0,
|
|
DefaultFunction::UnListData => 0,
|
|
DefaultFunction::UnIData => 0,
|
|
DefaultFunction::UnBData => 0,
|
|
DefaultFunction::EqualsData => 0,
|
|
DefaultFunction::SerialiseData => 0,
|
|
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,
|
|
}
|
|
}
|
|
|
|
pub fn call(
|
|
&self,
|
|
semantics: BuiltinSemantics,
|
|
args: &[Value],
|
|
logs: &mut Vec<String>,
|
|
) -> Result<Value, Error> {
|
|
match self {
|
|
DefaultFunction::AddInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
let result = arg1 + arg2;
|
|
|
|
let value = Value::integer(result);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::SubtractInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
let result = arg1 - arg2;
|
|
|
|
let value = Value::integer(result);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::MultiplyInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
let result = arg1 * arg2;
|
|
|
|
let value = Value::integer(result);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::DivideInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
if *arg2 != 0.into() {
|
|
let (result, _) = arg1.div_mod_floor(arg2);
|
|
|
|
let value = Value::integer(result);
|
|
|
|
Ok(value)
|
|
} else {
|
|
Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
|
|
}
|
|
}
|
|
DefaultFunction::QuotientInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
if *arg2 != 0.into() {
|
|
let (result, _) = arg1.div_rem(arg2);
|
|
|
|
let value = Value::integer(result);
|
|
|
|
Ok(value)
|
|
} else {
|
|
Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
|
|
}
|
|
}
|
|
DefaultFunction::RemainderInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
if *arg2 != 0.into() {
|
|
let (_, result) = arg1.div_rem(arg2);
|
|
|
|
let value = Value::integer(result);
|
|
|
|
Ok(value)
|
|
} else {
|
|
Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
|
|
}
|
|
}
|
|
DefaultFunction::ModInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
if *arg2 != 0.into() {
|
|
let (_, result) = arg1.div_mod_floor(arg2);
|
|
|
|
let value = Value::integer(result);
|
|
|
|
Ok(value)
|
|
} else {
|
|
Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
|
|
}
|
|
}
|
|
DefaultFunction::EqualsInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
let value = Value::bool(arg1 == arg2);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::LessThanInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
let value = Value::bool(arg1 < arg2);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::LessThanEqualsInteger => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
let value = Value::bool(arg1 <= arg2);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::AppendByteString => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
let arg2 = args[1].unwrap_byte_string()?;
|
|
|
|
let result = arg1.iter().copied().chain(arg2.iter().copied()).collect();
|
|
|
|
let value = Value::byte_string(result);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::ConsByteString => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_byte_string()?;
|
|
|
|
let byte: u8 = match semantics {
|
|
BuiltinSemantics::V1 => {
|
|
let wrap = arg1.mod_floor(&256.into());
|
|
|
|
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];
|
|
|
|
ret.extend(arg2.clone());
|
|
|
|
let value = Value::byte_string(ret);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::SliceByteString => {
|
|
let arg1 = args[0].unwrap_integer()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
let arg3 = args[2].unwrap_byte_string()?;
|
|
|
|
let skip: usize = if arg1.lt(&0.into()) {
|
|
0
|
|
} else {
|
|
arg1.try_into().unwrap()
|
|
};
|
|
let take: usize = if arg2.lt(&0.into()) {
|
|
0
|
|
} else {
|
|
arg2.try_into().unwrap()
|
|
};
|
|
|
|
let ret: Vec<u8> = arg3.iter().skip(skip).take(take).cloned().collect();
|
|
|
|
let value = Value::byte_string(ret);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::LengthOfByteString => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
|
|
let value = Value::integer(arg1.len().into());
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::IndexByteString => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
let arg2 = args[1].unwrap_integer()?;
|
|
|
|
let index: i128 = arg2.try_into().unwrap();
|
|
|
|
if 0 <= index && index < arg1.len() as i128 {
|
|
let ret = arg1[index as usize];
|
|
|
|
let value = Value::integer(ret.into());
|
|
|
|
Ok(value)
|
|
} else {
|
|
Err(Error::ByteStringOutOfBounds(arg2.clone(), arg1.to_vec()))
|
|
}
|
|
}
|
|
DefaultFunction::EqualsByteString => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
let arg2 = args[1].unwrap_byte_string()?;
|
|
|
|
let value = Value::bool(arg1 == arg2);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::LessThanByteString => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
let arg2 = args[1].unwrap_byte_string()?;
|
|
|
|
let value = Value::bool(arg1 < arg2);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::LessThanEqualsByteString => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
let arg2 = args[1].unwrap_byte_string()?;
|
|
|
|
let value = Value::bool(arg1 <= arg2);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::Sha2_256 => {
|
|
use cryptoxide::{digest::Digest, sha2::Sha256};
|
|
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
|
|
let mut hasher = Sha256::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::Sha3_256 => {
|
|
use cryptoxide::{digest::Digest, sha3::Sha3_256};
|
|
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
|
|
let mut hasher = Sha3_256::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::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};
|
|
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
|
|
let mut digest = [0u8; 32];
|
|
let mut context = Blake2b::new(32);
|
|
|
|
context.input(arg1);
|
|
context.result(&mut digest);
|
|
|
|
let value = Value::byte_string(digest.to_vec());
|
|
|
|
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;
|
|
|
|
let public_key = args[0].unwrap_byte_string()?;
|
|
let message = args[1].unwrap_byte_string()?;
|
|
let signature = args[2].unwrap_byte_string()?;
|
|
|
|
let public_key: [u8; 32] = public_key
|
|
.clone()
|
|
.try_into()
|
|
.map_err(|e: Vec<u8>| Error::UnexpectedEd25519PublicKeyLength(e.len()))?;
|
|
|
|
let signature: [u8; 64] = signature
|
|
.clone()
|
|
.try_into()
|
|
.map_err(|e: Vec<u8>| Error::UnexpectedEd25519SignatureLength(e.len()))?;
|
|
|
|
let valid = ed25519::verify(message, &public_key, &signature);
|
|
|
|
let value = Value::bool(valid);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::VerifyEcdsaSecp256k1Signature => {
|
|
let public_key = args[0].unwrap_byte_string()?;
|
|
let message = args[1].unwrap_byte_string()?;
|
|
let signature = args[2].unwrap_byte_string()?;
|
|
|
|
verify_ecdsa(public_key, message, signature)
|
|
}
|
|
DefaultFunction::VerifySchnorrSecp256k1Signature => {
|
|
let public_key = args[0].unwrap_byte_string()?;
|
|
let message = args[1].unwrap_byte_string()?;
|
|
let signature = args[2].unwrap_byte_string()?;
|
|
|
|
verify_schnorr(public_key, message, signature)
|
|
}
|
|
DefaultFunction::AppendString => {
|
|
let arg1 = args[0].unwrap_string()?;
|
|
let arg2 = args[1].unwrap_string()?;
|
|
|
|
let value = Value::string(format!("{arg1}{arg2}"));
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::EqualsString => {
|
|
let arg1 = args[0].unwrap_string()?;
|
|
let arg2 = args[1].unwrap_string()?;
|
|
|
|
let value = Value::bool(arg1 == arg2);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::EncodeUtf8 => {
|
|
let arg1 = args[0].unwrap_string()?;
|
|
|
|
let bytes = arg1.as_bytes().to_vec();
|
|
|
|
let value = Value::byte_string(bytes);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::DecodeUtf8 => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
|
|
let string = String::from_utf8(arg1.clone())?;
|
|
|
|
let value = Value::string(string);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::IfThenElse => {
|
|
let condition = args[0].unwrap_bool()?;
|
|
|
|
if *condition {
|
|
Ok(args[1].clone())
|
|
} else {
|
|
Ok(args[2].clone())
|
|
}
|
|
}
|
|
DefaultFunction::ChooseUnit => {
|
|
args[0].unwrap_unit()?;
|
|
|
|
Ok(args[1].clone())
|
|
}
|
|
DefaultFunction::Trace => {
|
|
let arg1 = args[0].unwrap_string()?;
|
|
|
|
logs.push(arg1.clone());
|
|
|
|
Ok(args[1].clone())
|
|
}
|
|
DefaultFunction::FstPair => {
|
|
let (_, _, first, _) = args[0].unwrap_pair()?;
|
|
|
|
let value = Value::Con(first.clone());
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::SndPair => {
|
|
let (_, _, _, second) = args[0].unwrap_pair()?;
|
|
|
|
let value = Value::Con(second.clone());
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::ChooseList => {
|
|
let (_, list) = args[0].unwrap_list()?;
|
|
|
|
if list.is_empty() {
|
|
Ok(args[1].clone())
|
|
} else {
|
|
Ok(args[2].clone())
|
|
}
|
|
}
|
|
DefaultFunction::MkCons => {
|
|
let item = args[0].unwrap_constant()?;
|
|
let (r#type, list) = args[1].unwrap_list()?;
|
|
|
|
if *r#type != Type::from(item) {
|
|
return Err(Error::TypeMismatch(Type::from(item), r#type.clone()));
|
|
}
|
|
|
|
let mut ret = vec![item.clone()];
|
|
|
|
ret.extend(list.clone());
|
|
|
|
let value = Value::list(r#type.clone(), ret);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::HeadList => {
|
|
let (_, list) = args[0].unwrap_list()?;
|
|
|
|
if list.is_empty() {
|
|
Err(Error::EmptyList(args[0].clone()))
|
|
} else {
|
|
let value = Value::Con(list[0].clone().into());
|
|
|
|
Ok(value)
|
|
}
|
|
}
|
|
DefaultFunction::TailList => {
|
|
let (r#type, list) = args[0].unwrap_list()?;
|
|
|
|
if list.is_empty() {
|
|
Err(Error::EmptyList(args[0].clone()))
|
|
} else {
|
|
let value = Value::list(r#type.clone(), list[1..].to_vec());
|
|
|
|
Ok(value)
|
|
}
|
|
}
|
|
DefaultFunction::NullList => {
|
|
let (_, list) = args[0].unwrap_list()?;
|
|
|
|
let value = Value::bool(list.is_empty());
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::ChooseData => {
|
|
let con = args[0].unwrap_data()?;
|
|
|
|
match con {
|
|
PlutusData::Constr(_) => Ok(args[1].clone()),
|
|
PlutusData::Map(_) => Ok(args[2].clone()),
|
|
PlutusData::Array(_) => Ok(args[3].clone()),
|
|
PlutusData::BigInt(_) => Ok(args[4].clone()),
|
|
PlutusData::BoundedBytes(_) => Ok(args[5].clone()),
|
|
}
|
|
}
|
|
DefaultFunction::ConstrData => {
|
|
let i = args[0].unwrap_integer()?;
|
|
let l = args[1].unwrap_data_list()?;
|
|
|
|
let data_list: Vec<PlutusData> = l
|
|
.iter()
|
|
.map(|item| match item {
|
|
Constant::Data(d) => d.clone(),
|
|
_ => unreachable!(),
|
|
})
|
|
.collect();
|
|
|
|
let i: u64 = i.try_into().unwrap();
|
|
|
|
let constr_data = Data::constr(i, data_list);
|
|
|
|
let value = Value::data(constr_data);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::MapData => {
|
|
let (r#type, list) = args[0].unwrap_list()?;
|
|
|
|
if *r#type != Type::Pair(Rc::new(Type::Data), Rc::new(Type::Data)) {
|
|
return Err(Error::TypeMismatch(
|
|
Type::List(Rc::new(Type::Pair(
|
|
Rc::new(Type::Data),
|
|
Rc::new(Type::Data),
|
|
))),
|
|
r#type.clone(),
|
|
));
|
|
}
|
|
|
|
let mut map = Vec::new();
|
|
|
|
for item in list {
|
|
let Constant::ProtoPair(Type::Data, Type::Data, left, right) = item else {
|
|
unreachable!()
|
|
};
|
|
|
|
let (Constant::Data(key), Constant::Data(value)) =
|
|
(left.as_ref(), right.as_ref())
|
|
else {
|
|
unreachable!()
|
|
};
|
|
|
|
map.push((key.clone(), value.clone()));
|
|
}
|
|
|
|
let value = Value::data(PlutusData::Map(map.into()));
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::ListData => {
|
|
let list = args[0].unwrap_data_list()?;
|
|
|
|
let data_list: Vec<PlutusData> = list
|
|
.iter()
|
|
.map(|item| match item {
|
|
Constant::Data(d) => d.clone(),
|
|
_ => unreachable!(),
|
|
})
|
|
.collect();
|
|
|
|
let value = Value::data(PlutusData::Array(data_list));
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::IData => {
|
|
let i = args[0].unwrap_integer()?;
|
|
|
|
let value = Value::data(PlutusData::BigInt(to_pallas_bigint(i)));
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::BData => {
|
|
let b = args[0].unwrap_byte_string()?;
|
|
|
|
let value = Value::data(PlutusData::BoundedBytes(b.clone().into()));
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::UnConstrData => match &args[0] {
|
|
v @ Value::Con(inner) => {
|
|
let Constant::Data(PlutusData::Constr(c)) = inner.as_ref() else {
|
|
return Err(Error::DeserialisationError(
|
|
"UnConstrData".to_string(),
|
|
v.clone(),
|
|
));
|
|
};
|
|
|
|
let constant = Constant::ProtoPair(
|
|
Type::Integer,
|
|
Type::List(Type::Data.into()),
|
|
Constant::Integer(
|
|
convert_tag_to_constr(c.tag)
|
|
.unwrap_or_else(|| c.any_constructor.unwrap())
|
|
.into(),
|
|
)
|
|
.into(),
|
|
Constant::ProtoList(
|
|
Type::Data,
|
|
c.fields
|
|
.deref()
|
|
.iter()
|
|
.map(|d| Constant::Data(d.clone()))
|
|
.collect(),
|
|
)
|
|
.into(),
|
|
);
|
|
|
|
let value = Value::Con(constant.into());
|
|
|
|
Ok(value)
|
|
}
|
|
v => Err(Error::NotAConstant(v.clone())),
|
|
},
|
|
DefaultFunction::UnMapData => match &args[0] {
|
|
v @ Value::Con(inner) => {
|
|
let Constant::Data(PlutusData::Map(m)) = inner.as_ref() else {
|
|
return Err(Error::DeserialisationError(
|
|
"UnMapData".to_string(),
|
|
v.clone(),
|
|
));
|
|
};
|
|
|
|
let constant = Constant::ProtoList(
|
|
Type::Pair(Type::Data.into(), Type::Data.into()),
|
|
m.deref()
|
|
.iter()
|
|
.map(|p| -> Constant {
|
|
Constant::ProtoPair(
|
|
Type::Data,
|
|
Type::Data,
|
|
Constant::Data(p.0.clone()).into(),
|
|
Constant::Data(p.1.clone()).into(),
|
|
)
|
|
})
|
|
.collect(),
|
|
);
|
|
|
|
let value = Value::Con(constant.into());
|
|
|
|
Ok(value)
|
|
}
|
|
v => Err(Error::NotAConstant(v.clone())),
|
|
},
|
|
DefaultFunction::UnListData => match &args[0] {
|
|
v @ Value::Con(inner) => {
|
|
let Constant::Data(PlutusData::Array(l)) = inner.as_ref() else {
|
|
return Err(Error::DeserialisationError(
|
|
"UnListData".to_string(),
|
|
v.clone(),
|
|
));
|
|
};
|
|
|
|
let value = Value::list(
|
|
Type::Data,
|
|
l.deref()
|
|
.iter()
|
|
.map(|d| Constant::Data(d.clone()))
|
|
.collect(),
|
|
);
|
|
|
|
Ok(value)
|
|
}
|
|
v => Err(Error::NotAConstant(v.clone())),
|
|
},
|
|
DefaultFunction::UnIData => match &args[0] {
|
|
v @ Value::Con(inner) => {
|
|
let Constant::Data(PlutusData::BigInt(b)) = inner.as_ref() else {
|
|
return Err(Error::DeserialisationError(
|
|
"UnIData".to_string(),
|
|
v.clone(),
|
|
));
|
|
};
|
|
|
|
let value = Value::integer(from_pallas_bigint(b));
|
|
|
|
Ok(value)
|
|
}
|
|
v => Err(Error::NotAConstant(v.clone())),
|
|
},
|
|
DefaultFunction::UnBData => match &args[0] {
|
|
v @ Value::Con(inner) => {
|
|
let Constant::Data(PlutusData::BoundedBytes(b)) = inner.as_ref() else {
|
|
return Err(Error::DeserialisationError(
|
|
"UnBData".to_string(),
|
|
v.clone(),
|
|
));
|
|
};
|
|
|
|
let value = Value::byte_string(b.to_vec());
|
|
|
|
Ok(value)
|
|
}
|
|
v => Err(Error::NotAConstant(v.clone())),
|
|
},
|
|
DefaultFunction::EqualsData => {
|
|
let d1 = args[0].unwrap_data()?;
|
|
let d2 = args[1].unwrap_data()?;
|
|
|
|
let value = Value::bool(d1.eq(d2));
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::SerialiseData => {
|
|
let d = args[0].unwrap_data()?;
|
|
|
|
let serialized_data = plutus_data_to_bytes(d).unwrap();
|
|
|
|
let value = Value::byte_string(serialized_data);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::MkPairData => {
|
|
let d1 = args[0].unwrap_data()?;
|
|
let d2 = args[1].unwrap_data()?;
|
|
|
|
let constant = Constant::ProtoPair(
|
|
Type::Data,
|
|
Type::Data,
|
|
Constant::Data(d1.clone()).into(),
|
|
Constant::Data(d2.clone()).into(),
|
|
);
|
|
|
|
let value = Value::Con(constant.into());
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::MkNilData => {
|
|
args[0].unwrap_unit()?;
|
|
|
|
let value = Value::list(Type::Data, vec![]);
|
|
|
|
Ok(value)
|
|
}
|
|
DefaultFunction::MkNilPairData => {
|
|
args[0].unwrap_unit()?;
|
|
|
|
let constant = Constant::ProtoList(
|
|
Type::Pair(Rc::new(Type::Data), Rc::new(Type::Data)),
|
|
vec![],
|
|
);
|
|
|
|
let value = Value::Con(constant.into());
|
|
|
|
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::<blst::blst_scalar>();
|
|
|
|
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 _,
|
|
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 out = arg1.compress();
|
|
|
|
let constant = Constant::ByteString(out.to_vec());
|
|
|
|
Ok(Value::Con(constant.into()))
|
|
}
|
|
DefaultFunction::Bls12_381_G1_Uncompress => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
|
|
let out = blst::blst_p1::uncompress(arg1)?;
|
|
|
|
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::<blst::blst_scalar>();
|
|
|
|
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 _,
|
|
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 out = arg1.compress();
|
|
|
|
let constant = Constant::ByteString(out.to_vec());
|
|
|
|
Ok(Value::Con(constant.into()))
|
|
}
|
|
DefaultFunction::Bls12_381_G2_Uncompress => {
|
|
let arg1 = args[0].unwrap_byte_string()?;
|
|
|
|
let out = blst::blst_p2::uncompress(arg1)?;
|
|
|
|
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()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait Compressable {
|
|
fn compress(&self) -> Vec<u8>;
|
|
|
|
fn uncompress(bytes: &[u8]) -> Result<Self, Error>
|
|
where
|
|
Self: std::marker::Sized;
|
|
}
|
|
|
|
impl Compressable for blst::blst_p1 {
|
|
fn compress(&self) -> Vec<u8> {
|
|
let mut out = [0; BLST_P1_COMPRESSED_SIZE];
|
|
|
|
unsafe {
|
|
blst::blst_p1_compress(&mut out as *mut _, self);
|
|
};
|
|
|
|
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 {
|
|
fn compress(&self) -> Vec<u8> {
|
|
let mut out = [0; BLST_P2_COMPRESSED_SIZE];
|
|
|
|
unsafe {
|
|
blst::blst_p2_compress(&mut out as *mut _, self);
|
|
};
|
|
|
|
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> {
|
|
if (121..=127).contains(&tag) {
|
|
Some(tag - 121)
|
|
} else if (1280..=1400).contains(&tag) {
|
|
Some(tag - 1280 + 7)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn convert_constr_to_tag(constr: u64) -> Option<u64> {
|
|
if (0..=6).contains(&constr) {
|
|
Some(121 + constr)
|
|
} else if (7..=127).contains(&constr) {
|
|
Some(1280 - 7 + constr)
|
|
} else {
|
|
None // 102 otherwise
|
|
}
|
|
}
|
|
|
|
pub static ANY_TAG: u64 = 102;
|
|
|
|
#[cfg(not(target_family = "wasm"))]
|
|
fn verify_ecdsa(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<Value, Error> {
|
|
use secp256k1::{ecdsa::Signature, Message, PublicKey, Secp256k1};
|
|
|
|
let secp = Secp256k1::verification_only();
|
|
|
|
let public_key = PublicKey::from_slice(public_key)?;
|
|
|
|
let signature = Signature::from_compact(signature)?;
|
|
|
|
let message = Message::from_slice(message)?;
|
|
|
|
let valid = secp.verify_ecdsa(&message, &signature, &public_key);
|
|
|
|
Ok(Value::Con(Constant::Bool(valid.is_ok()).into()))
|
|
}
|
|
|
|
/// Unlike the Haskell implementation the schnorr verification function in Aiken doesn't allow for arbitrary message sizes (at the moment).
|
|
/// The message needs to be 32 bytes (ideally prehashed, but not a requirement).
|
|
#[cfg(not(target_family = "wasm"))]
|
|
fn verify_schnorr(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<Value, Error> {
|
|
use secp256k1::{schnorr::Signature, Message, Secp256k1, XOnlyPublicKey};
|
|
|
|
let secp = Secp256k1::verification_only();
|
|
|
|
let public_key = XOnlyPublicKey::from_slice(public_key)?;
|
|
|
|
let signature = Signature::from_slice(signature)?;
|
|
|
|
let message = Message::from_slice(message)?;
|
|
|
|
let valid = secp.verify_schnorr(&signature, &message, &public_key);
|
|
|
|
Ok(Value::Con(Constant::Bool(valid.is_ok()).into()))
|
|
}
|
|
|
|
#[cfg(target_family = "wasm")]
|
|
fn verify_ecdsa(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<Value, Error> {
|
|
use k256::ecdsa::{self, signature::hazmat::PrehashVerifier};
|
|
|
|
let verifying_key = ecdsa::VerifyingKey::try_from(public_key)?;
|
|
|
|
let signature = ecdsa::Signature::try_from(signature)?;
|
|
|
|
let valid = verifying_key.verify_prehash(message, &signature);
|
|
|
|
Ok(Value::Con(Constant::Bool(valid.is_ok()).into()))
|
|
}
|
|
|
|
#[cfg(target_family = "wasm")]
|
|
fn verify_schnorr(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<Value, Error> {
|
|
use k256::schnorr::{self, signature::hazmat::PrehashVerifier};
|
|
|
|
let verifying_key = schnorr::VerifyingKey::from_bytes(public_key)?;
|
|
|
|
let signature = schnorr::Signature::try_from(signature)?;
|
|
|
|
let valid = verifying_key.verify_prehash(message, &signature);
|
|
|
|
Ok(Value::Con(Constant::Bool(valid.is_ok()).into()))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::{convert_constr_to_tag, convert_tag_to_constr};
|
|
|
|
#[test]
|
|
fn compact_tag_range() {
|
|
assert_eq!(convert_constr_to_tag(0), Some(121));
|
|
assert_eq!(convert_constr_to_tag(1), Some(122));
|
|
assert_eq!(convert_constr_to_tag(6), Some(127));
|
|
assert_ne!(convert_constr_to_tag(7), Some(128)); // This is not allowed
|
|
}
|
|
#[test]
|
|
fn compact_tag_mid_range() {
|
|
assert_eq!(convert_constr_to_tag(7), Some(1280));
|
|
assert_eq!(convert_constr_to_tag(8), Some(1281));
|
|
assert_eq!(convert_constr_to_tag(100), Some(1373));
|
|
assert_eq!(convert_constr_to_tag(127), Some(1400));
|
|
assert_ne!(convert_constr_to_tag(128), Some(1401)); // This is not allowed
|
|
}
|
|
|
|
#[test]
|
|
fn any_range() {
|
|
assert_eq!(convert_constr_to_tag(128), None);
|
|
assert_eq!(
|
|
convert_constr_to_tag(128).map_or(Some(128), |_| None),
|
|
Some(128)
|
|
);
|
|
assert_eq!(convert_constr_to_tag(123124125125), None);
|
|
assert_eq!(convert_constr_to_tag(1).map_or(Some(1), |_| None), None); // This is a compact tag
|
|
}
|
|
|
|
#[test]
|
|
fn to_compact_tag() {
|
|
assert_eq!(convert_tag_to_constr(121), Some(0));
|
|
assert_eq!(convert_tag_to_constr(122), Some(1));
|
|
assert_eq!(convert_tag_to_constr(127), Some(6));
|
|
assert_eq!(convert_tag_to_constr(128), None); // This can never happen actually. Pallas sorts that out already during deserialization.
|
|
}
|
|
#[test]
|
|
fn to_compact_tag_mid() {
|
|
assert_eq!(convert_tag_to_constr(1280), Some(7));
|
|
assert_eq!(convert_tag_to_constr(1281), Some(8));
|
|
assert_eq!(convert_tag_to_constr(1400), Some(127));
|
|
assert_eq!(convert_tag_to_constr(1401), None); // This can never happen actually. Pallas sorts that out already during deserialization.
|
|
}
|
|
|
|
#[test]
|
|
fn to_any_tag() {
|
|
assert_eq!(convert_tag_to_constr(102), None);
|
|
}
|
|
}
|