use crate::schnorr::random_scalar;
use anyhow::{Context, Result, anyhow};
use blstrs::{G1Affine, G1Projective, Scalar};
use hex;
use hex::FromHex;
use pallas_primitives::{
BoundedBytes, Fragment,
alonzo::{Constr, MaybeIndefArray, PlutusData},
};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Hash, Clone, Default)]
pub struct Register {
pub generator: String,
pub public_value: String,
}
impl Register {
pub fn new(generator: String, public_value: String) -> Self {
Self {
generator,
public_value,
}
}
pub fn create(sk: Scalar) -> Result<Self> {
let compressed_g1_generator: &str = "97F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB";
let g1_generator: G1Affine = G1Affine::from_compressed(
&hex::decode(compressed_g1_generator)
.context("Failed to decode generator hex")?
.try_into()
.map_err(|e| anyhow::anyhow!("{e:?}"))?,
)
.into_option()
.ok_or_else(|| anyhow!("Failed to decompress generator"))?;
let public_value: G1Projective = G1Projective::from(g1_generator) * sk;
Ok(Self {
generator: hex::encode(g1_generator.to_compressed()),
public_value: hex::encode(public_value.to_compressed()),
})
}
pub fn to_vec(&self) -> Result<Vec<u8>> {
let generator_vector: Vec<u8> =
Vec::from_hex(&self.generator).context("Invalid hex string")?;
let public_value_vector: Vec<u8> =
Vec::from_hex(&self.public_value).context("Invalid hex string")?;
let plutus_data: PlutusData = PlutusData::Constr(Constr {
tag: 121,
any_constructor: None,
fields: MaybeIndefArray::Indef(vec![
PlutusData::BoundedBytes(BoundedBytes::from(generator_vector)),
PlutusData::BoundedBytes(BoundedBytes::from(public_value_vector)),
]),
});
plutus_data
.encode_fragment()
.map_err(|e| anyhow!("Failed to encode PlutusData fragment: {e}"))
}
pub fn rerandomize(self) -> Result<Self> {
let g1: G1Affine = G1Affine::from_compressed(
&hex::decode(self.generator)
.context("Failed to decode generator hex")?
.try_into()
.map_err(|e| anyhow::anyhow!("{e:?}"))?,
)
.into_option()
.ok_or_else(|| anyhow!("Failed to decompress generator"))?;
let u: G1Affine = G1Affine::from_compressed(
&hex::decode(self.public_value)
.context("Failed to decode public value hex")?
.try_into()
.map_err(|e| anyhow::anyhow!("{e:?}"))?,
)
.into_option()
.ok_or_else(|| anyhow!("Failed to decompress generator"))?;
let d: Scalar = random_scalar();
let g1_randomized: G1Projective = G1Projective::from(g1) * d;
let u_randomized: G1Projective = G1Projective::from(u) * d;
Ok(Self {
generator: hex::encode(g1_randomized.to_compressed()),
public_value: hex::encode(u_randomized.to_compressed()),
})
}
pub fn is_owned(&self, sk: Scalar) -> Result<bool> {
let g1: G1Affine = G1Affine::from_compressed(
&hex::decode(&self.generator)
.context("Failed to decode generator hex")?
.try_into()
.map_err(|e| anyhow::anyhow!("{e:?}"))?,
)
.into_option()
.ok_or_else(|| anyhow!("Failed to decompress generator"))?;
let g_x: G1Projective = G1Projective::from(g1) * sk;
Ok(hex::encode(g_x.to_compressed()) == self.public_value)
}
pub fn is_valid(&self) -> Result<bool> {
let g1: G1Affine = G1Affine::from_compressed(
&hex::decode(&self.generator)
.context("Failed to decode generator hex")?
.try_into()
.map_err(|e| anyhow::anyhow!("{e:?}"))?,
)
.into_option()
.ok_or_else(|| anyhow!("Failed to decompress generator"))?;
let u: G1Affine = G1Affine::from_compressed(
&hex::decode(&self.public_value)
.context("Failed to decode public value hex")?
.try_into()
.map_err(|e| anyhow::anyhow!("{e:?}"))?,
)
.into_option()
.ok_or_else(|| anyhow!("Failed to decompress generator"))?;
Ok(g1.is_on_curve().into()
&& g1.is_torsion_free().into()
&& u.is_on_curve().into()
&& u.is_torsion_free().into())
}
}