• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ergoplatform / sigma-rust / 11835992403

14 Nov 2024 11:08AM UTC coverage: 78.658% (+0.005%) from 78.653%
11835992403

Pull #779

github

web-flow
Merge 3a7127227 into 250f06581
Pull Request #779: Replace num256 with bnum

65 of 70 new or added lines in 7 files covered. (92.86%)

8 existing lines in 3 files now uncovered.

11009 of 13996 relevant lines covered (78.66%)

3.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.03
/ergotree-ir/src/sigma_protocol/sigma_boolean.rs
1
//! Sigma boolean types
2

3
use self::cand::Cand;
4
use self::cor::Cor;
5
use self::cthreshold::Cthreshold;
6

7
use crate::ergo_tree::{ErgoTree, ErgoTreeError};
8
use crate::has_opcode::{HasOpCode, HasStaticOpCode};
9
use crate::mir::constant::Constant;
10
use crate::mir::expr::Expr;
11
use crate::serialization::op_code::OpCode;
12
use crate::serialization::SigmaSerializable;
13
use ergo_chain_types::EcPoint;
14
use std::convert::TryFrom;
15
use std::fmt::Formatter;
16

17
extern crate derive_more;
18
use bounded_vec::BoundedVec;
19
use derive_more::From;
20
use derive_more::Into;
21
use derive_more::TryInto;
22

23
pub mod cand;
24
pub mod cor;
25
pub mod cthreshold;
26

27
/// Sigma conjecture items type with bounds check (1..=255)
28
pub type SigmaConjectureItems<T> = BoundedVec<T, 1, 255>;
29

30
/// Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol.
31
#[derive(PartialEq, Eq, Debug, Clone)]
32
pub struct ProveDlog {
33
    /// public key
34
    pub h: Box<EcPoint>,
35
}
36

37
impl ProveDlog {
38
    /// create new public key
39
    pub fn new(ecpoint: EcPoint) -> ProveDlog {
10✔
40
        ProveDlog {
41
            h: Box::new(ecpoint),
42
        }
43
    }
44
}
45

46
impl HasStaticOpCode for ProveDlog {
47
    const OP_CODE: OpCode = OpCode::PROVE_DLOG;
48
}
49

50
impl From<EcPoint> for ProveDlog {
51
    fn from(p: EcPoint) -> Self {
1✔
52
        ProveDlog::new(p)
1✔
53
    }
54
}
55

56
impl std::fmt::Display for ProveDlog {
57
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
58
        write!(f, "proveDlog({})", self.h)
×
59
    }
60
}
61

62
/// Construct a new SigmaProp value representing public key of Diffie Hellman signature protocol.
63
/// Used in a proof that of equality of discrete logarithms (i.e., a proof of a Diffie-Hellman tuple):
64
/// given group elements g, h, u, v, the proof convinces a verifier that the prover knows `w` such
65
/// that `u = g^w` and `v = h^w`, without revealing `w`
66
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
67
#[derive(PartialEq, Eq, Debug, Clone)]
68
pub struct ProveDhTuple {
69
    /// Generator g
70
    pub g: Box<EcPoint>,
71
    /// Point h
72
    pub h: Box<EcPoint>,
73
    /// Point `u = g^w`
74
    pub u: Box<EcPoint>,
75
    /// Point `v= h^w`
76
    pub v: Box<EcPoint>,
77
}
78

79
impl HasStaticOpCode for ProveDhTuple {
80
    const OP_CODE: OpCode = OpCode::PROVE_DIFFIE_HELLMAN_TUPLE;
81
}
82

83
impl ProveDhTuple {
84
    /// Create new instance
85
    pub fn new(g: EcPoint, h: EcPoint, u: EcPoint, v: EcPoint) -> Self {
5✔
86
        Self {
87
            g: g.into(),
5✔
88
            h: h.into(),
10✔
89
            u: u.into(),
10✔
90
            v: v.into(),
5✔
91
        }
92
    }
93
}
94

95
impl std::fmt::Display for ProveDhTuple {
96
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
UNCOV
97
        write!(
×
98
            f,
99
            "ProveDhTuple(g: {}, h: {}, u: {}, v: {})",
100
            self.g, self.h, self.u, self.v
101
        )
102
    }
103
}
104

105
/// Sigma proposition
106
#[derive(PartialEq, Eq, Debug, Clone, From, derive_more::Display)]
107
pub enum SigmaProofOfKnowledgeTree {
108
    /// public key of Diffie Hellman signature protocol
109
    ProveDhTuple(ProveDhTuple),
110
    /// public key of discrete logarithm signature protocol
111
    ProveDlog(ProveDlog),
112
}
113

114
impl HasOpCode for SigmaProofOfKnowledgeTree {
115
    fn op_code(&self) -> OpCode {
8✔
116
        match self {
8✔
117
            SigmaProofOfKnowledgeTree::ProveDhTuple(dh) => dh.op_code(),
5✔
118
            SigmaProofOfKnowledgeTree::ProveDlog(dlog) => dlog.op_code(),
9✔
119
        }
120
    }
121
}
122

123
/// Conjunctions for sigma propositions
124
#[derive(PartialEq, Eq, Debug, Clone)]
125
pub enum SigmaConjecture {
126
    /// AND
127
    Cand(Cand),
128
    /// OR
129
    Cor(Cor),
130
    /// THRESHOLD
131
    Cthreshold(Cthreshold),
132
}
133

134
impl HasOpCode for SigmaConjecture {
135
    fn op_code(&self) -> OpCode {
5✔
136
        match self {
5✔
137
            SigmaConjecture::Cand(cand) => cand.op_code(),
5✔
138
            SigmaConjecture::Cor(cor) => cor.op_code(),
5✔
139
            SigmaConjecture::Cthreshold(ct) => ct.op_code(),
5✔
140
        }
141
    }
142
}
143

144
impl std::fmt::Display for SigmaConjecture {
145
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
146
        match self {
×
147
            SigmaConjecture::Cand(c) => write!(f, "{}", c),
×
148
            SigmaConjecture::Cor(c) => write!(f, "{}", c),
×
149
            SigmaConjecture::Cthreshold(c) => write!(f, "{}", c),
×
150
        }
151
    }
152
}
153

154
/// Algebraic data type of sigma proposition expressions
155
/// Values of this type are used as values of SigmaProp type
156
#[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
157
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
158
#[cfg_attr(
159
    feature = "json",
160
    serde(
161
        try_from = "crate::chain::json::sigma_protocol::SigmaBooleanJson",
162
        into = "crate::chain::json::sigma_protocol::SigmaBooleanJson"
163
    )
164
)]
165
pub enum SigmaBoolean {
166
    /// Represents boolean values (true/false)
167
    TrivialProp(bool),
168
    /// Sigma proposition
169
    ProofOfKnowledge(SigmaProofOfKnowledgeTree),
170
    /// Conjunctions for sigma propositions
171
    SigmaConjecture(SigmaConjecture),
172
}
173

174
impl HasOpCode for SigmaBoolean {
175
    /// get OpCode for serialization
176
    fn op_code(&self) -> OpCode {
8✔
177
        match self {
9✔
178
            SigmaBoolean::ProofOfKnowledge(kt) => kt.op_code(),
7✔
179
            SigmaBoolean::SigmaConjecture(sc) => sc.op_code(),
5✔
180
            SigmaBoolean::TrivialProp(tp) => {
1✔
181
                if *tp {
1✔
182
                    OpCode::TRIVIAL_PROP_TRUE
1✔
183
                } else {
184
                    OpCode::TRIVIAL_PROP_FALSE
×
185
                }
186
            }
187
        }
188
    }
189
}
190

191
/// Failed to extract specified underlying type from SigmaBoolean
192
#[derive(PartialEq, Eq, Debug, Clone)]
193
pub struct ConversionError;
194

195
impl TryInto<ProveDlog> for SigmaBoolean {
196
    type Error = ConversionError;
197
    fn try_into(self) -> Result<ProveDlog, Self::Error> {
1✔
198
        match self {
1✔
199
            SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pd)) => Ok(pd),
1✔
200
            _ => Err(ConversionError),
×
201
        }
202
    }
203
}
204

205
impl From<ProveDlog> for SigmaBoolean {
206
    fn from(v: ProveDlog) -> Self {
5✔
207
        SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(v))
5✔
208
    }
209
}
210

211
impl TryInto<ProveDhTuple> for SigmaBoolean {
212
    type Error = ConversionError;
213
    fn try_into(self) -> Result<ProveDhTuple, Self::Error> {
×
214
        match self {
×
215
            SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDhTuple(pdh)) => Ok(pdh),
×
216
            _ => Err(ConversionError),
×
217
        }
218
    }
219
}
220

221
impl From<ProveDhTuple> for SigmaBoolean {
222
    fn from(v: ProveDhTuple) -> Self {
5✔
223
        SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDhTuple(v))
5✔
224
    }
225
}
226

227
impl TryInto<Cand> for SigmaBoolean {
228
    type Error = ConversionError;
229
    fn try_into(self) -> Result<Cand, Self::Error> {
×
230
        match self {
×
231
            SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(c)) => Ok(c),
×
232
            _ => Err(ConversionError),
×
233
        }
234
    }
235
}
236

237
impl From<Cand> for SigmaBoolean {
238
    fn from(v: Cand) -> Self {
5✔
239
        SigmaBoolean::SigmaConjecture(SigmaConjecture::Cand(v))
5✔
240
    }
241
}
242

243
impl TryInto<Cor> for SigmaBoolean {
244
    type Error = ConversionError;
245
    fn try_into(self) -> Result<Cor, Self::Error> {
×
246
        match self {
×
247
            SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(c)) => Ok(c),
×
248
            _ => Err(ConversionError),
×
249
        }
250
    }
251
}
252

253
impl From<Cor> for SigmaBoolean {
254
    fn from(v: Cor) -> Self {
5✔
255
        SigmaBoolean::SigmaConjecture(SigmaConjecture::Cor(v))
5✔
256
    }
257
}
258

259
impl TryInto<Cthreshold> for SigmaBoolean {
260
    type Error = ConversionError;
261
    fn try_into(self) -> Result<Cthreshold, Self::Error> {
×
262
        match self {
×
263
            SigmaBoolean::SigmaConjecture(SigmaConjecture::Cthreshold(c)) => Ok(c),
×
264
            _ => Err(ConversionError),
×
265
        }
266
    }
267
}
268

269
impl From<Cthreshold> for SigmaBoolean {
270
    fn from(v: Cthreshold) -> Self {
5✔
271
        SigmaBoolean::SigmaConjecture(SigmaConjecture::Cthreshold(v))
5✔
272
    }
273
}
274

275
impl std::fmt::Display for SigmaBoolean {
276
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
277
        match self {
×
278
            SigmaBoolean::TrivialProp(b) => write!(f, "sigmaProp({})", b),
×
279
            SigmaBoolean::ProofOfKnowledge(kt) => write!(f, "{}", kt),
×
280
            SigmaBoolean::SigmaConjecture(sc) => write!(f, "{}", sc),
×
281
        }
282
    }
283
}
284

285
/// Proposition which can be proven and verified by sigma protocol.
286
#[derive(PartialEq, Eq, Debug, Clone, From, Into, derive_more::Display)]
287
pub struct SigmaProp(SigmaBoolean);
288

289
impl SigmaProp {
290
    /// create new sigma proposition from [`SigmaBoolean`] value
291
    pub fn new(sbool: SigmaBoolean) -> Self {
5✔
292
        SigmaProp(sbool)
5✔
293
    }
294

295
    /// get [`SigmaBoolean`] value
296
    pub fn value(&self) -> &SigmaBoolean {
9✔
297
        &self.0
298
    }
299

300
    /// Serialized bytes of a SigmaProp value
301
    pub fn prop_bytes(&self) -> Result<Vec<u8>, ErgoTreeError> {
1✔
302
        // in order to have comparisons like  `box.propositionBytes == pk.propBytes` we need to make sure
303
        // the same serialization method is used in both cases
304
        let c: Constant = self.clone().into();
1✔
305
        let e: Expr = c.into();
1✔
306
        let ergo_tree: ErgoTree = e.try_into()?;
1✔
307
        Ok(ergo_tree.sigma_serialize_bytes()?)
2✔
308
    }
309
}
310

311
impl TryFrom<SigmaProp> for bool {
312
    type Error = ConversionError;
313

314
    fn try_from(value: SigmaProp) -> Result<Self, Self::Error> {
1✔
315
        value.0.try_into().map_err(|_| ConversionError)
1✔
316
    }
317
}
318

319
impl From<ProveDlog> for SigmaProp {
320
    fn from(pd: ProveDlog) -> Self {
3✔
321
        SigmaProp(SigmaBoolean::ProofOfKnowledge(
3✔
322
            SigmaProofOfKnowledgeTree::ProveDlog(pd),
3✔
323
        ))
324
    }
325
}
326

327
impl From<ProveDhTuple> for SigmaProp {
328
    fn from(dh: ProveDhTuple) -> Self {
×
329
        SigmaProp(SigmaBoolean::ProofOfKnowledge(
×
330
            SigmaProofOfKnowledgeTree::ProveDhTuple(dh),
×
331
        ))
332
    }
333
}
334

335
/// Arbitrary impl for ProveDlog
336
#[cfg(feature = "arbitrary")]
337
#[allow(clippy::unwrap_used)]
338
mod arbitrary {
339
    use super::*;
340
    use proptest::collection::vec;
341
    use proptest::prelude::*;
342

343
    impl Arbitrary for ProveDlog {
344
        type Parameters = ();
345
        type Strategy = BoxedStrategy<Self>;
346

347
        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
6✔
348
            (any::<EcPoint>()).prop_map(ProveDlog::new).boxed()
9✔
349
        }
350
    }
351

352
    impl Arbitrary for ProveDhTuple {
353
        type Parameters = ();
354
        type Strategy = BoxedStrategy<Self>;
355

356
        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
10✔
357
            (
358
                any::<EcPoint>(),
8✔
359
                any::<EcPoint>(),
19✔
360
                any::<EcPoint>(),
19✔
361
                any::<EcPoint>(),
10✔
362
            )
363
                .prop_map(|(g, h, u, v)| ProveDhTuple::new(g, h, u, v))
10✔
364
                .boxed()
365
        }
366
    }
367

368
    pub fn primitive_type_value() -> BoxedStrategy<SigmaBoolean> {
10✔
369
        prop_oneof![
20✔
370
            any::<ProveDlog>().prop_map_into(),
8✔
371
            any::<ProveDhTuple>().prop_map_into(),
17✔
372
            // TODO: enable and fix sigma_conj eval tests
373
            // any::<bool>().prop_map_into(),
374
        ]
375
        .boxed()
376
    }
377

378
    impl Arbitrary for SigmaBoolean {
379
        type Parameters = ();
380
        type Strategy = BoxedStrategy<Self>;
381

382
        fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
10✔
383
            primitive_type_value()
8✔
384
                .prop_recursive(1, 8, 4, |elem| {
7✔
385
                    prop_oneof![
24✔
386
                        vec(elem.clone(), 2..=4)
12✔
387
                            .prop_map(|elems| Cand {
10✔
388
                                items: elems.try_into().unwrap()
5✔
389
                            })
390
                            .prop_map_into(),
391
                        vec(elem.clone(), 2..=4)
12✔
392
                            .prop_map(|elems| Cor {
10✔
393
                                items: elems.try_into().unwrap()
5✔
394
                            })
395
                            .prop_map_into(),
396
                        vec(elem, 2..=5)
12✔
397
                            .prop_map(|elems| Cthreshold {
10✔
398
                                k: (elems.len() - 1) as u8,
10✔
399
                                children: elems.try_into().unwrap()
10✔
400
                            })
401
                            .prop_map_into(),
402
                    ]
403
                })
404
                .boxed()
405
        }
406
    }
407

408
    impl Arbitrary for SigmaProp {
409
        type Parameters = ();
410
        type Strategy = BoxedStrategy<Self>;
411

412
        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
10✔
413
            (any::<SigmaBoolean>()).prop_map(SigmaProp::new).boxed()
8✔
414
        }
415
    }
416
}
417

418
#[allow(clippy::panic)]
419
#[cfg(test)]
420
#[allow(clippy::panic)]
421
mod tests {
422
    use super::*;
423
    use crate::serialization::sigma_serialize_roundtrip;
424
    use proptest::prelude::*;
425

426
    proptest! {
427

428
        #[test]
429
        fn sigma_boolean_ser_roundtrip(
430
            v in any::<SigmaBoolean>()) {
431
                prop_assert_eq![sigma_serialize_roundtrip(&v), v]
432
        }
433
    }
434
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc