seedelf_crypto/
register.rs1use crate::schnorr::random_scalar;
2use anyhow::{Context, Result, anyhow};
3use blstrs::{G1Affine, G1Projective, Scalar};
4use hex;
5use hex::FromHex;
6use pallas_primitives::{
7 BoundedBytes, Fragment,
8 alonzo::{Constr, MaybeIndefArray, PlutusData},
9};
10use serde::{Deserialize, Serialize};
11
12#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Hash, Clone, Default)]
20pub struct Register {
21 pub generator: String,
22 pub public_value: String,
23}
24
25impl Register {
26 pub fn new(generator: String, public_value: String) -> Self {
33 Self {
34 generator,
35 public_value,
36 }
37 }
38
39 pub fn create(sk: Scalar) -> Result<Self> {
52 let compressed_g1_generator: &str = "97F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB";
54
55 let g1_generator: G1Affine = G1Affine::from_compressed(
56 &hex::decode(compressed_g1_generator)
57 .context("Failed to decode generator hex")?
58 .try_into()
59 .map_err(|e| anyhow::anyhow!("{e:?}"))?,
60 )
61 .into_option()
62 .ok_or_else(|| anyhow!("Failed to decompress generator"))?;
63
64 let public_value: G1Projective = G1Projective::from(g1_generator) * sk;
65
66 Ok(Self {
68 generator: hex::encode(g1_generator.to_compressed()),
69 public_value: hex::encode(public_value.to_compressed()),
70 })
71 }
72
73 pub fn to_vec(&self) -> Result<Vec<u8>> {
83 let generator_vector: Vec<u8> =
85 Vec::from_hex(&self.generator).context("Invalid hex string")?;
86 let public_value_vector: Vec<u8> =
87 Vec::from_hex(&self.public_value).context("Invalid hex string")?;
88 let plutus_data: PlutusData = PlutusData::Constr(Constr {
90 tag: 121,
91 any_constructor: None,
92 fields: MaybeIndefArray::Indef(vec![
93 PlutusData::BoundedBytes(BoundedBytes::from(generator_vector)),
94 PlutusData::BoundedBytes(BoundedBytes::from(public_value_vector)),
95 ]),
96 });
97 plutus_data
98 .encode_fragment()
99 .map_err(|e| anyhow!("Failed to encode PlutusData fragment: {e}"))
100 }
101
102 pub fn rerandomize(self) -> Result<Self> {
111 let g1: G1Affine = G1Affine::from_compressed(
113 &hex::decode(self.generator)
114 .context("Failed to decode generator hex")?
115 .try_into()
116 .map_err(|e| anyhow::anyhow!("{e:?}"))?,
117 )
118 .into_option()
119 .ok_or_else(|| anyhow!("Failed to decompress generator"))?;
120
121 let u: G1Affine = G1Affine::from_compressed(
123 &hex::decode(self.public_value)
124 .context("Failed to decode public value hex")?
125 .try_into()
126 .map_err(|e| anyhow::anyhow!("{e:?}"))?,
127 )
128 .into_option()
129 .ok_or_else(|| anyhow!("Failed to decompress generator"))?;
130
131 let d: Scalar = random_scalar();
133
134 let g1_randomized: G1Projective = G1Projective::from(g1) * d;
136 let u_randomized: G1Projective = G1Projective::from(u) * d;
137
138 Ok(Self {
140 generator: hex::encode(g1_randomized.to_compressed()),
141 public_value: hex::encode(u_randomized.to_compressed()),
142 })
143 }
144
145 pub fn is_owned(&self, sk: Scalar) -> Result<bool> {
159 let g1: G1Affine = G1Affine::from_compressed(
160 &hex::decode(&self.generator)
161 .context("Failed to decode generator hex")?
162 .try_into()
163 .map_err(|e| anyhow::anyhow!("{e:?}"))?,
164 )
165 .into_option()
166 .ok_or_else(|| anyhow!("Failed to decompress generator"))?;
167
168 let g_x: G1Projective = G1Projective::from(g1) * sk;
169
170 Ok(hex::encode(g_x.to_compressed()) == self.public_value)
171 }
172
173 pub fn is_valid(&self) -> Result<bool> {
174 let g1: G1Affine = G1Affine::from_compressed(
176 &hex::decode(&self.generator)
177 .context("Failed to decode generator hex")?
178 .try_into()
179 .map_err(|e| anyhow::anyhow!("{e:?}"))?,
180 )
181 .into_option()
182 .ok_or_else(|| anyhow!("Failed to decompress generator"))?;
183
184 let u: G1Affine = G1Affine::from_compressed(
186 &hex::decode(&self.public_value)
187 .context("Failed to decode public value hex")?
188 .try_into()
189 .map_err(|e| anyhow::anyhow!("{e:?}"))?,
190 )
191 .into_option()
192 .ok_or_else(|| anyhow!("Failed to decompress generator"))?;
193
194 Ok(g1.is_on_curve().into()
195 && g1.is_torsion_free().into()
196 && u.is_on_curve().into()
197 && u.is_torsion_free().into())
198 }
199}