use super::*;
use ark_scale::{
HOST_CALL,
rw::InputAsRead,
scale::{Compact, Decode, Input},
};
use ark_serialize::{CanonicalDeserialize, Compress, Validate};
use gear_core::limited::LimitedStr;
const IS_COMPRESSED: Compress = ark_scale::is_compressed(HOST_CALL);
const IS_VALIDATED: Validate = ark_scale::is_validated(HOST_CALL);
pub fn multi_miller_loop<Gas: BlsOpsGasCost, Ops: Bls12_381Ops>(
mut payload: &[u8],
context: &mut BuiltinContext,
) -> Result<Response, BuiltinActorError> {
let a = decode_vec::<Gas, _>(&mut payload, context)?;
let b = decode_vec::<Gas, _>(&mut payload, context)?;
let mut slice = a.as_slice();
let mut reader = InputAsRead(&mut slice);
let count =
u64::deserialize_with_mode(&mut reader, IS_COMPRESSED, IS_VALIDATED).map_err(|_| {
log::debug!("Failed to decode items count in a",);
BuiltinActorError::DecodingError
})?;
let mut slice = b.as_slice();
let mut reader = InputAsRead(&mut slice);
match u64::deserialize_with_mode(&mut reader, IS_COMPRESSED, IS_VALIDATED) {
Ok(count_b) if count_b != count => {
return Err(BuiltinActorError::Custom(LimitedStr::from_small_str(
"Multi Miller loop: uneven item count",
)));
}
Err(_) => return Err(BuiltinActorError::DecodingError),
Ok(_) => (),
}
let gas_cost = Gas::bls12_381_multi_miller_loop(count as u32);
context.try_charge_gas(gas_cost)?;
Ops::multi_miller_loop(a, b).map(Response::MultiMillerLoop)
}
pub fn final_exponentiation<Gas: BlsOpsGasCost, Ops: Bls12_381Ops>(
mut payload: &[u8],
context: &mut BuiltinContext,
) -> Result<Response, BuiltinActorError> {
let f = decode_vec::<Gas, _>(&mut payload, context)?;
let to_spend = Gas::bls12_381_final_exponentiation();
context.try_charge_gas(to_spend)?;
Ops::final_exponentiation(f).map(Response::FinalExponentiation)
}
pub fn msm<Gas: BlsOpsGasCost>(
mut payload: &[u8],
context: &mut BuiltinContext,
gas_cost_fn: impl FnOnce(u32) -> u64,
msm_impl: impl FnOnce(Vec<u8>, Vec<u8>) -> Result<Response, BuiltinActorError>,
) -> Result<Response, BuiltinActorError> {
let bases = decode_vec::<Gas, _>(&mut payload, context)?;
let scalars = decode_vec::<Gas, _>(&mut payload, context)?;
let mut slice = bases.as_slice();
let mut reader = InputAsRead(&mut slice);
let count =
u64::deserialize_with_mode(&mut reader, IS_COMPRESSED, IS_VALIDATED).map_err(|_| {
log::debug!("Failed to decode items count in bases");
BuiltinActorError::DecodingError
})?;
let mut slice = scalars.as_slice();
let mut reader = InputAsRead(&mut slice);
match u64::deserialize_with_mode(&mut reader, IS_COMPRESSED, IS_VALIDATED) {
Ok(count_b) if count_b != count => {
return Err(BuiltinActorError::Custom(LimitedStr::from_small_str(
"Multi scalar multiplication: uneven item count",
)));
}
Err(_) => {
log::debug!("Failed to decode items count in scalars");
return Err(BuiltinActorError::DecodingError);
}
Ok(_) => (),
}
let to_spend = gas_cost_fn(count as u32);
context.try_charge_gas(to_spend)?;
msm_impl(bases, scalars)
}
pub fn projective_multiplication<Gas: BlsOpsGasCost>(
mut payload: &[u8],
context: &mut BuiltinContext,
gas_cost_fn: impl FnOnce(u32) -> u64,
mul_impl: impl FnOnce(Vec<u8>, Vec<u8>) -> Result<Response, BuiltinActorError>,
) -> Result<Response, BuiltinActorError> {
let base = decode_vec::<Gas, _>(&mut payload, context)?;
let scalar = decode_vec::<Gas, _>(&mut payload, context)?;
let mut slice = scalar.as_slice();
let mut reader = InputAsRead(&mut slice);
let count =
u64::deserialize_with_mode(&mut reader, IS_COMPRESSED, IS_VALIDATED).map_err(|_| {
log::debug!("Failed to decode count of items in scalar");
BuiltinActorError::DecodingError
})?;
let to_spend = gas_cost_fn(count as u32);
context.try_charge_gas(to_spend)?;
mul_impl(base, scalar)
}
pub fn aggregate_g1<Gas: BlsOpsGasCost, Ops: Bls12_381Ops>(
mut payload: &[u8],
context: &mut BuiltinContext,
) -> Result<Response, BuiltinActorError> {
let points = decode_vec::<Gas, _>(&mut payload, context)?;
let mut slice = points.as_slice();
let mut reader = InputAsRead(&mut slice);
let count =
u64::deserialize_with_mode(&mut reader, IS_COMPRESSED, IS_VALIDATED).map_err(|_| {
log::debug!("Failed to decode count of items in points");
BuiltinActorError::DecodingError
})?;
let to_spend = Gas::bls12_381_aggregate_g1(count as u32);
context.try_charge_gas(to_spend)?;
Ops::aggregate_g1(points).map(Response::AggregateG1)
}
pub fn map_to_g2affine<Gas: BlsOpsGasCost, Ops: Bls12_381Ops>(
mut payload: &[u8],
context: &mut BuiltinContext,
) -> Result<Response, BuiltinActorError> {
let len = Compact::<u32>::decode(&mut payload)
.map(u32::from)
.map_err(|_| BuiltinActorError::DecodingError)?;
if len != payload.len() as u32 {
return Err(BuiltinActorError::DecodingError);
}
let to_spend = Gas::bls12_381_map_to_g2affine(len);
context.try_charge_gas(to_spend)?;
Ops::map_to_g2affine(payload.to_vec()).map(Response::MapToG2Affine)
}
fn decode_vec<Gas: BlsOpsGasCost, I: Input>(
input: &mut I,
context: &mut BuiltinContext,
) -> Result<Vec<u8>, BuiltinActorError> {
let len = Compact::<u32>::decode(input).map(u32::from).map_err(|_| {
log::debug!("Failed to scale-decode length of the vector",);
BuiltinActorError::DecodingError
})?;
let to_spend = Gas::decode_bytes(len);
context.try_charge_gas(to_spend)?;
let mut items = vec![0u8; len as usize];
let bytes_slice = items.as_mut_slice();
input.read(bytes_slice).map(|_| items).map_err(|_| {
log::debug!("Failed to scale-decode vector data",);
BuiltinActorError::DecodingError
})
}