1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use crate::serialization::{
sigma_byte_reader::SigmaByteRead, SerializationError, SigmaSerializable,
};
use k256::{AffinePoint, ProjectivePoint, PublicKey, Scalar};
use sigma_ser::vlq_encode;
use elliptic_curve::weierstrass::public_key::FromPublicKey;
use std::{
io,
ops::{Add, Mul, Neg},
};
use super::private_input::DlogProverInput;
#[derive(PartialEq, Debug, Clone)]
pub struct EcPoint(ProjectivePoint);
impl EcPoint {
pub const GROUP_SIZE: usize = 33;
}
impl Eq for EcPoint {}
impl Mul<&EcPoint> for EcPoint {
type Output = EcPoint;
fn mul(self, other: &EcPoint) -> EcPoint {
EcPoint(ProjectivePoint::add(self.0, &other.0))
}
}
impl Neg for EcPoint {
type Output = EcPoint;
fn neg(self) -> EcPoint {
EcPoint(ProjectivePoint::neg(self.0))
}
}
pub fn generator() -> EcPoint {
EcPoint(ProjectivePoint::generator())
}
pub const fn identity() -> EcPoint {
EcPoint(ProjectivePoint::identity())
}
pub fn is_identity(ge: &EcPoint) -> bool {
*ge == identity()
}
pub fn inverse(ec: &EcPoint) -> EcPoint {
-ec.clone()
}
pub fn exponentiate(base: &EcPoint, exponent: &Scalar) -> EcPoint {
if !is_identity(base) {
EcPoint(base.0 * exponent)
} else {
base.clone()
}
}
pub fn random_element() -> EcPoint {
let sk = DlogProverInput::random();
exponentiate(&generator(), &sk.w)
}
pub fn random_scalar_in_group_range() -> Scalar {
use rand::rngs::OsRng;
Scalar::generate_vartime(&mut OsRng)
}
impl SigmaSerializable for EcPoint {
fn sigma_serialize<W: vlq_encode::WriteSigmaVlqExt>(&self, w: &mut W) -> Result<(), io::Error> {
let caff = self.0.to_affine();
if bool::from(caff.is_some()) {
let pubkey = PublicKey::Compressed(caff.unwrap().into());
w.write_all(pubkey.as_bytes())?;
} else {
let zeroes = [0u8; EcPoint::GROUP_SIZE];
w.write_all(&zeroes)?;
}
Ok(())
}
fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SerializationError> {
let mut buf = [0; EcPoint::GROUP_SIZE];
r.read_exact(&mut buf[..])?;
if buf[0] != 0 {
let pubkey = PublicKey::from_bytes(&buf[..]).ok_or_else(|| {
SerializationError::Misc("failed to parse PK from bytes".to_string())
})?;
let cp = AffinePoint::from_public_key(&pubkey);
if bool::from(cp.is_none()) {
Err(SerializationError::Misc(
"failed to get affine point from PK".to_string(),
))
} else {
Ok(EcPoint(ProjectivePoint::from(cp.unwrap())))
}
} else {
Ok(EcPoint(ProjectivePoint::identity()))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::serialization::sigma_serialize_roundtrip;
use proptest::prelude::*;
impl Arbitrary for EcPoint {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
prop_oneof![Just(generator()), Just(identity()), Just(random_element()),].boxed()
}
}
proptest! {
#[test]
fn ser_roundtrip(v in any::<EcPoint>()) {
prop_assert_eq![sigma_serialize_roundtrip(&v), v];
}
}
}