ergotree_interpreter/sigma_protocol/
private_input.rs1use std::convert::TryInto;
3use std::fmt::Formatter;
4
5use ergo_chain_types::EcPoint;
6use ergotree_ir::serialization::SigmaSerializable;
7use ergotree_ir::sigma_protocol::dlog_group;
8use ergotree_ir::sigma_protocol::sigma_boolean::ProveDhTuple;
9use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
10
11use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
12
13extern crate derive_more;
14use derive_more::From;
15use k256::elliptic_curve::PrimeField;
16use num_bigint::BigUint;
17use num_traits::ToPrimitive;
18
19use super::crypto_utils;
20use super::wscalar::Wscalar;
21
22#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
24#[cfg_attr(feature = "json", serde(transparent))]
25#[derive(PartialEq, Eq, Clone, derive_more::From)]
26pub struct DlogProverInput {
27 pub w: Wscalar,
29}
30
31impl std::fmt::Debug for DlogProverInput {
32 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
33 "DLOGPI:***".fmt(f)
35 }
36}
37
38impl DlogProverInput {
39 pub const SIZE_BYTES: usize = 32;
41
42 pub fn random() -> DlogProverInput {
44 DlogProverInput {
45 w: dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng()).into(),
46 }
47 }
48
49 pub fn from_bytes(bytes: &[u8; DlogProverInput::SIZE_BYTES]) -> Option<DlogProverInput> {
52 k256::Scalar::from_repr((*bytes).into())
53 .map(|s| DlogProverInput::from(Wscalar::from(s)))
54 .into()
55 }
56
57 pub fn from_base16_str(str: String) -> Option<DlogProverInput> {
60 base16::decode(&str)
61 .ok()
62 .and_then(|bytes| bytes.as_slice().try_into().ok().map(Self::from_bytes))
63 .flatten()
64 }
65
66 pub fn from_biguint(b: BigUint) -> Option<DlogProverInput> {
69 #[allow(clippy::unwrap_used)]
71 pub fn biguint_to_32bytes(x: &BigUint) -> [u8; 32] {
72 let mask = BigUint::from(u8::MAX);
73 let mut bytes = [0u8; 32];
74 (0..32).for_each(|i| {
75 bytes[i] = ((x >> ((31 - i) * 8)) as BigUint & &mask).to_u8().unwrap();
76 });
77 bytes
78 }
79 let bytes = biguint_to_32bytes(&b);
80 Self::from_bytes(&bytes)
81 }
82
83 pub fn to_bytes(&self) -> [u8; DlogProverInput::SIZE_BYTES] {
85 self.w.as_scalar_ref().to_bytes().into()
86 }
87
88 pub fn public_image(&self) -> ProveDlog {
90 let g = ergo_chain_types::ec_point::generator();
92 ProveDlog::new(ergo_chain_types::ec_point::exponentiate(
93 &g,
94 self.w.as_scalar_ref(),
95 ))
96 }
97
98 pub fn is_zero(&self) -> bool {
100 self.w.as_scalar_ref().is_zero().into()
101 }
102}
103
104#[derive(PartialEq, Eq, Clone)]
109#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
110pub struct DhTupleProverInput {
111 #[cfg_attr(feature = "json", serde(rename = "secret"))]
113 pub w: Wscalar,
114 #[cfg_attr(feature = "json", serde(flatten))]
116 pub common_input: ProveDhTuple,
117}
118
119impl std::fmt::Debug for DhTupleProverInput {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 "DHTPI:***".fmt(f)
123 }
124}
125
126impl DhTupleProverInput {
127 pub const SIZE_BYTES: usize = DlogProverInput::SIZE_BYTES + EcPoint::GROUP_SIZE * 4;
129
130 #[allow(clippy::many_single_char_names)]
132 pub fn random() -> DhTupleProverInput {
133 use ergo_chain_types::ec_point::{exponentiate, generator};
134 let g = generator();
135 let h = exponentiate(
136 &generator(),
137 &dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng()),
138 );
139 let w = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
140 let u = exponentiate(&g, &w);
141 let v = exponentiate(&h, &w);
142 let common_input = ProveDhTuple::new(g, h, u, v);
143 DhTupleProverInput {
144 w: w.into(),
145 common_input,
146 }
147 }
148
149 pub fn public_image(&self) -> &ProveDhTuple {
151 &self.common_input
152 }
153
154 #[allow(clippy::unwrap_used)]
156 pub fn to_bytes(&self) -> [u8; DhTupleProverInput::SIZE_BYTES] {
157 let mut bytes = Vec::with_capacity(DhTupleProverInput::SIZE_BYTES);
158 bytes.extend_from_slice(self.w.as_scalar_ref().to_bytes().as_slice());
159 bytes.extend_from_slice(&self.common_input.g.sigma_serialize_bytes().unwrap());
160 bytes.extend_from_slice(&self.common_input.h.sigma_serialize_bytes().unwrap());
161 bytes.extend_from_slice(&self.common_input.u.sigma_serialize_bytes().unwrap());
162 bytes.extend_from_slice(&self.common_input.v.sigma_serialize_bytes().unwrap());
163 bytes.try_into().unwrap()
164 }
165
166 #[allow(clippy::unwrap_used)]
170 pub fn from_bytes(bytes: &[u8; DhTupleProverInput::SIZE_BYTES]) -> Option<DhTupleProverInput> {
171 let w_bytes: &[u8; DlogProverInput::SIZE_BYTES] =
172 &bytes[..DlogProverInput::SIZE_BYTES].try_into().unwrap();
173 let g_bytes: &[u8; EcPoint::GROUP_SIZE] = &bytes
174 [DlogProverInput::SIZE_BYTES..DlogProverInput::SIZE_BYTES + EcPoint::GROUP_SIZE]
175 .try_into()
176 .unwrap();
177 let h_bytes: &[u8; EcPoint::GROUP_SIZE] = &bytes[DlogProverInput::SIZE_BYTES
178 + EcPoint::GROUP_SIZE
179 ..DlogProverInput::SIZE_BYTES + EcPoint::GROUP_SIZE * 2]
180 .try_into()
181 .unwrap();
182 let u_bytes: &[u8; EcPoint::GROUP_SIZE] = &bytes[DlogProverInput::SIZE_BYTES
183 + EcPoint::GROUP_SIZE * 2
184 ..DlogProverInput::SIZE_BYTES + EcPoint::GROUP_SIZE * 3]
185 .try_into()
186 .unwrap();
187 let v_bytes: &[u8; EcPoint::GROUP_SIZE] = &bytes[DlogProverInput::SIZE_BYTES
188 + EcPoint::GROUP_SIZE * 3
189 ..DlogProverInput::SIZE_BYTES + EcPoint::GROUP_SIZE * 4]
190 .try_into()
191 .unwrap();
192 Self::from_bytes_fields(w_bytes, g_bytes, h_bytes, u_bytes, v_bytes)
193 }
194
195 pub fn from_bytes_fields(
199 w_bytes: &[u8; DlogProverInput::SIZE_BYTES],
200 g_bytes: &[u8; EcPoint::GROUP_SIZE],
201 h_bytes: &[u8; EcPoint::GROUP_SIZE],
202 u_bytes: &[u8; EcPoint::GROUP_SIZE],
203 v_bytes: &[u8; EcPoint::GROUP_SIZE],
204 ) -> Option<DhTupleProverInput> {
205 let w: Option<Wscalar> = k256::Scalar::from_repr((*w_bytes).into())
206 .map(Wscalar::from)
207 .into();
208 let g = EcPoint::sigma_parse_bytes(&g_bytes[..EcPoint::GROUP_SIZE]).ok()?;
209 let h = EcPoint::sigma_parse_bytes(&h_bytes[..EcPoint::GROUP_SIZE]).ok()?;
210 let u = EcPoint::sigma_parse_bytes(&u_bytes[..EcPoint::GROUP_SIZE]).ok()?;
211 let v = EcPoint::sigma_parse_bytes(&v_bytes[..EcPoint::GROUP_SIZE]).ok()?;
212 w.map(|w| DhTupleProverInput {
213 w,
214 common_input: ProveDhTuple::new(g, h, u, v),
215 })
216 }
217}
218
219#[derive(PartialEq, Eq, Debug, Clone, From)]
221pub enum PrivateInput {
222 DlogProverInput(DlogProverInput),
224 DhTupleProverInput(DhTupleProverInput),
226}
227
228impl PrivateInput {
229 pub fn public_image(&self) -> SigmaBoolean {
231 match self {
232 PrivateInput::DlogProverInput(dl) => dl.public_image().into(),
233 PrivateInput::DhTupleProverInput(dht) => dht.public_image().clone().into(),
234 }
235 }
236}
237
238#[cfg(feature = "arbitrary")]
239pub(crate) mod arbitrary {
241
242 use super::*;
243 use proptest::prelude::*;
244
245 impl Arbitrary for DlogProverInput {
246 type Parameters = ();
247 type Strategy = BoxedStrategy<Self>;
248 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
249 prop_oneof![
250 Just(DlogProverInput::random()),
251 Just(DlogProverInput::random()),
252 Just(DlogProverInput::random()),
253 Just(DlogProverInput::random()),
254 Just(DlogProverInput::random()),
255 ]
256 .boxed()
257 }
258 }
259
260 impl Arbitrary for DhTupleProverInput {
261 type Parameters = ();
262 type Strategy = BoxedStrategy<Self>;
263 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
264 prop_oneof![
265 Just(DhTupleProverInput::random()),
266 Just(DhTupleProverInput::random()),
267 Just(DhTupleProverInput::random()),
268 Just(DhTupleProverInput::random()),
269 Just(DhTupleProverInput::random()),
270 ]
271 .boxed()
272 }
273 }
274
275 impl Arbitrary for PrivateInput {
276 type Parameters = ();
277 type Strategy = BoxedStrategy<Self>;
278 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
279 prop_oneof![
280 any::<DlogProverInput>().prop_map_into(),
281 any::<DhTupleProverInput>().prop_map_into(),
282 ]
283 .boxed()
284 }
285 }
286}
287
288#[cfg(test)]
289#[cfg(feature = "arbitrary")]
290mod tests {}