use crate::ir_ergo_box::IrBoxId;
use crate::sigma_protocol::sigma_boolean::ProveDlog;
use crate::sigma_protocol::sigma_boolean::SigmaBoolean;
use crate::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
use crate::sigma_protocol::{dlog_group::EcPoint, sigma_boolean::SigmaProp};
use crate::types::stype::LiftIntoSType;
use crate::types::stype::SType;
use impl_trait_for_tuples::impl_for_tuples;
use num_bigint::BigInt;
use std::convert::TryInto;
mod constant_placeholder;
pub(crate) use constant_placeholder::*;
use super::value::CollKind;
use super::value::NativeColl;
use super::value::StoreWrapped;
use super::value::Value;
use thiserror::Error;
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Constant {
pub tpe: SType,
pub v: Value,
}
impl From<bool> for Constant {
fn from(v: bool) -> Constant {
Constant {
tpe: bool::stype(),
v: v.into(),
}
}
}
impl From<i8> for Constant {
fn from(v: i8) -> Constant {
Constant {
tpe: i8::stype(),
v: v.into(),
}
}
}
impl From<i16> for Constant {
fn from(v: i16) -> Constant {
Constant {
tpe: i16::stype(),
v: v.into(),
}
}
}
impl From<i32> for Constant {
fn from(v: i32) -> Constant {
Constant {
tpe: i32::stype(),
v: v.into(),
}
}
}
impl From<i64> for Constant {
fn from(v: i64) -> Constant {
Constant {
tpe: i64::stype(),
v: v.into(),
}
}
}
impl From<SigmaProp> for Constant {
fn from(v: SigmaProp) -> Constant {
Constant {
tpe: SType::SSigmaProp,
v: Box::new(v).into(),
}
}
}
impl From<EcPoint> for Constant {
fn from(v: EcPoint) -> Constant {
Constant {
tpe: SType::SGroupElement,
v: v.into(),
}
}
}
impl From<IrBoxId> for Constant {
fn from(b: IrBoxId) -> Self {
Constant {
tpe: SType::SBox,
v: b.into(),
}
}
}
impl From<Vec<u8>> for Constant {
fn from(v: Vec<u8>) -> Self {
Constant {
tpe: SType::SColl(Box::new(SType::SByte)),
v: Value::Coll(CollKind::NativeColl(NativeColl::CollByte(
v.into_iter().map(|b| b as i8).collect(),
))),
}
}
}
impl From<Vec<i8>> for Constant {
fn from(v: Vec<i8>) -> Constant {
Constant {
tpe: SType::SColl(Box::new(SType::SByte)),
v: v.into(),
}
}
}
impl<T: LiftIntoSType + StoreWrapped + Into<Value>> From<Vec<T>> for Constant {
fn from(v: Vec<T>) -> Self {
Constant {
tpe: Vec::<T>::stype(),
v: v.into(),
}
}
}
impl<T: LiftIntoSType + Into<Value>> From<Option<T>> for Constant {
fn from(opt: Option<T>) -> Self {
Constant {
tpe: SType::SOption(Box::new(T::stype())),
v: opt.into(),
}
}
}
impl From<ProveDlog> for Constant {
fn from(v: ProveDlog) -> Self {
Constant::from(SigmaProp::from(SigmaBoolean::from(
SigmaProofOfKnowledgeTree::from(v),
)))
}
}
impl From<BigInt> for Constant {
fn from(b: BigInt) -> Self {
Constant {
tpe: SType::SBigInt,
v: b.into(),
}
}
}
#[allow(clippy::clippy::from_over_into)]
#[impl_for_tuples(2, 4)]
impl Into<Constant> for Tuple {
fn into(self) -> Constant {
let constants: Vec<Constant> = [for_tuples!( #( Tuple.into() ),* )].to_vec();
let (types, values): (Vec<SType>, Vec<Value>) =
constants.into_iter().map(|c| (c.tpe, c.v)).unzip();
Constant {
tpe: SType::STuple(types.try_into().unwrap()),
v: Value::Tup(values.try_into().unwrap()),
}
}
}
pub trait TryExtractInto<F> {
fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError>;
}
impl<F> TryExtractInto<F> for F {
fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError> {
T::try_extract_from(self)
}
}
#[derive(Error, PartialEq, Eq, Debug, Clone)]
#[error("Failed TryExtractFrom: {0}")]
pub struct TryExtractFromError(pub String);
pub trait TryExtractFrom<T>: Sized {
fn try_extract_from(v: T) -> Result<Self, TryExtractFromError>;
}
impl<T: TryExtractFrom<Value>> TryExtractFrom<Constant> for T {
fn try_extract_from(cv: Constant) -> Result<Self, TryExtractFromError> {
T::try_extract_from(cv.v)
}
}
#[cfg(feature = "arbitrary")]
pub(crate) mod arbitrary {
use std::convert::TryFrom;
use super::*;
use crate::types::stuple::STuple;
use num_bigint::ToBigInt;
use proptest::collection::vec;
use proptest::prelude::*;
extern crate derive_more;
use derive_more::From;
use derive_more::TryInto;
fn primitive_type_value() -> BoxedStrategy<Constant> {
prop_oneof![
any::<bool>().prop_map_into(),
any::<i8>().prop_map_into(),
any::<i16>().prop_map_into(),
any::<i32>().prop_map_into(),
any::<i64>().prop_map_into(),
any::<i64>().prop_map(|v| v.to_bigint().unwrap().into()),
any::<EcPoint>().prop_map_into(),
any::<SigmaProp>().prop_map_into(),
vec(any::<i8>(), 0..100).prop_map_into(),
]
.boxed()
}
fn coll_from_constant(c: Constant, length: usize) -> Constant {
Constant {
tpe: SType::SColl(Box::new(c.tpe.clone())),
v: Value::Coll(if c.tpe == SType::SByte {
let mut values: Vec<i8> = Vec::with_capacity(length);
let byte: i8 = c.v.try_extract_into().unwrap();
for _ in 0..length {
values.push(byte);
}
CollKind::NativeColl(NativeColl::CollByte(values))
} else {
let mut values: Vec<Value> = Vec::with_capacity(length);
for _ in 0..length {
values.push(c.v.clone());
}
CollKind::WrappedColl {
elem_tpe: c.tpe,
items: values,
}
}),
}
}
fn const_with_type(tpe: SType) -> BoxedStrategy<Constant> {
match tpe {
SType::SAny => any::<Constant>(),
SType::SBoolean => any::<bool>().prop_map_into().boxed(),
SType::SByte => any::<i8>().prop_map_into().boxed(),
SType::SShort => any::<i16>().prop_map_into().boxed(),
SType::SInt => any::<i32>().prop_map_into().boxed(),
SType::SLong => any::<i64>().prop_map_into().boxed(),
SType::SBigInt => any::<i64>()
.prop_map(|v| v.to_bigint().unwrap().into())
.boxed(),
SType::SGroupElement => any::<EcPoint>().prop_map_into().boxed(),
SType::SSigmaProp => any::<SigmaProp>().prop_map_into().boxed(),
SType::SColl(elem_tpe) => match *elem_tpe {
SType::SByte => vec(any::<u8>(), 0..400).prop_map_into().boxed(),
SType::SBoolean => vec(any::<bool>(), 0..400).prop_map_into().boxed(),
_ => todo!(),
},
_ => todo!("{0:?} not yet implemented", tpe),
}
}
impl Default for ArbConstantParams {
fn default() -> Self {
ArbConstantParams::AnyWithDepth(1)
}
}
#[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
pub enum ArbConstantParams {
AnyWithDepth(u8),
Exact(SType),
}
impl Arbitrary for Constant {
type Parameters = ArbConstantParams;
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
match args {
ArbConstantParams::AnyWithDepth(depth) => {
prop_oneof![primitive_type_value().prop_recursive(
depth as u32,
16,
8,
|elem| {
prop_oneof![
elem.clone().prop_map(|c| coll_from_constant(c, 0)),
elem.clone().prop_map(|c| coll_from_constant(c, 1)),
elem.clone().prop_map(|c| coll_from_constant(c, 2)),
elem.clone().prop_map(|c| coll_from_constant(c, 10)),
vec(elem, 2..=4).prop_map(|constants| Constant {
tpe: SType::STuple(
STuple::try_from(
constants
.clone()
.into_iter()
.map(|c| c.tpe)
.collect::<Vec<SType>>()
)
.unwrap()
),
v: Value::Tup(
constants
.into_iter()
.map(|c| c.v)
.collect::<Vec<Value>>()
.try_into()
.unwrap()
)
}),
]
}
)]
.boxed()
}
ArbConstantParams::Exact(tpe) => const_with_type(tpe),
}
}
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use core::fmt;
use num_bigint::ToBigInt;
use proptest::prelude::*;
fn test_constant_roundtrip<T>(v: T)
where
T: TryExtractInto<T> + TryExtractFrom<Value> + Into<Constant> + fmt::Debug + Eq + Clone,
{
let constant: Constant = v.clone().into();
let v_extracted: T = constant.try_extract_into::<T>().unwrap();
assert_eq!(v, v_extracted);
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(8))]
#[test]
fn bool_roundtrip(v in any::<bool>()) {
test_constant_roundtrip(v);
}
#[test]
fn i8_roundtrip(v in any::<i8>()) {
test_constant_roundtrip(v);
}
#[test]
fn i16_roundtrip(v in any::<i16>()) {
test_constant_roundtrip(v);
}
#[test]
fn i32_roundtrip(v in any::<i32>()) {
test_constant_roundtrip(v);
}
#[test]
fn i64_roundtrip(v in any::<i64>()) {
test_constant_roundtrip(v);
}
#[test]
fn bigint_roundtrip(raw in any::<i64>()) {
let v = raw.to_bigint().unwrap();
test_constant_roundtrip(v);
}
#[test]
fn group_element_roundtrip(v in any::<EcPoint>()) {
test_constant_roundtrip(v);
}
#[test]
fn sigma_prop_roundtrip(v in any::<SigmaProp>()) {
test_constant_roundtrip(v);
}
#[test]
fn vec_i8_roundtrip(v in any::<Vec<i8>>()) {
test_constant_roundtrip(v);
}
#[test]
fn vec_u8_roundtrip(v in any::<Vec<u8>>()) {
test_constant_roundtrip(v);
}
#[test]
fn vec_i16_roundtrip(v in any::<Vec<i16>>()) {
test_constant_roundtrip(v);
}
#[test]
fn vec_i32_roundtrip(v in any::<Vec<i32>>()) {
test_constant_roundtrip(v);
}
#[test]
fn vec_i64_roundtrip(v in any::<Vec<i64>>()) {
test_constant_roundtrip(v);
}
#[test]
fn vec_bigint_roundtrip(raw in any::<Vec<i64>>()) {
let v: Vec<BigInt> = raw.into_iter().map(|i| i.to_bigint().unwrap()).collect();
test_constant_roundtrip(v);
}
#[test]
fn vec_option_bigint_roundtrip(raw in any::<Vec<i64>>()) {
let v: Vec<Option<BigInt>> = raw.into_iter().map(|i| i.to_bigint()).collect();
test_constant_roundtrip(v);
}
#[test]
fn vec_sigmaprop_roundtrip(v in any::<Vec<SigmaProp>>()) {
test_constant_roundtrip(v);
}
#[test]
fn option_primitive_type_roundtrip(v in any::<Option<i64>>()) {
test_constant_roundtrip(v);
}
#[test]
fn option_nested_vector_type_roundtrip(v in any::<Option<Vec<(i64, bool)>>>()) {
test_constant_roundtrip(v);
}
#[test]
fn option_nested_tuple_type_roundtrip(v in any::<Option<(i64, bool)>>()) {
test_constant_roundtrip(v);
}
#[test]
fn tuple_primitive_types_roundtrip(v in any::<(i64, bool)>()) {
test_constant_roundtrip(v);
}
#[test]
fn tuple_nested_types_roundtrip(v in any::<(Option<i64>, Vec<SigmaProp>)>()) {
test_constant_roundtrip(v);
}
}
}