dkls23/
proto.rs

1// Copyright (c) Silence Laboratories Pte. Ltd. All Rights Reserved.
2// This software is licensed under the Silence Laboratories License Agreement.
3
4use std::mem;
5
6use k256::{
7    elliptic_curve::{group::GroupEncoding, PrimeField},
8    AffinePoint, NonZeroScalar, ProjectivePoint, Scalar,
9};
10use x25519_dalek::PublicKey;
11
12use sl_mpc_mate::{math::GroupPolynomial, message::*, ByteArray};
13use sl_oblivious::zkproofs::DLogProof;
14
15use crate::setup::{ProtocolParticipant, ABORT_MESSAGE_TAG};
16
17mod encrypted;
18mod scheme;
19mod signed;
20
21/// tags
22pub mod tags;
23
24pub use encrypted::{EncryptedMessage, EncryptionScheme, Scheme};
25pub use signed::SignedMessage;
26pub use tags::{FilteredMsgRelay, Round};
27
28/// External representation of a point on a curve
29pub type PointBytes = [u8; 33];
30
31/// External Scalar representation
32pub type ScalarBytes = [u8; 32]; // KAPPA_BYTES
33
34pub use sl_mpc_mate::{
35    coord::Relay,
36    message::{MessageTag, MsgHdr},
37};
38
39/// Encode AffinePoint
40pub fn encode_affine(&a: &AffinePoint) -> PointBytes {
41    a.to_bytes().into()
42}
43
44/// Encode AffinePoint
45pub fn decode_affine(bytes: &PointBytes) -> Option<AffinePoint> {
46    let mut repr = <AffinePoint as GroupEncoding>::Repr::default();
47    AsMut::<[u8]>::as_mut(&mut repr).copy_from_slice(bytes);
48
49    AffinePoint::from_bytes(&repr).into()
50}
51
52/// Encode ProjectivePoint
53pub fn encode_point(p: &ProjectivePoint) -> PointBytes {
54    encode_affine(&p.to_affine())
55}
56
57/// Decode ProjectivePoint
58pub fn decode_point(bytes: &PointBytes) -> Option<ProjectivePoint> {
59    let mut repr = <ProjectivePoint as GroupEncoding>::Repr::default();
60    AsMut::<[u8]>::as_mut(&mut repr).copy_from_slice(bytes);
61
62    ProjectivePoint::from_bytes(&repr).into()
63}
64
65/// Encode a scalar
66pub fn encode_scalar(s: &Scalar) -> ScalarBytes {
67    s.to_bytes().into()
68}
69
70/// Decode a scalar
71pub fn decode_scalar(bytes: &ScalarBytes) -> Option<Scalar> {
72    let mut repr = <Scalar as PrimeField>::Repr::default();
73    AsMut::<[u8]>::as_mut(&mut repr).copy_from_slice(bytes);
74
75    Scalar::from_repr(repr).into()
76}
77
78/// Decode a NonZeroScalar
79pub fn decode_nonzero(bytes: &ScalarBytes) -> Option<NonZeroScalar> {
80    NonZeroScalar::new(decode_scalar(bytes)?).into()
81}
82
83/// Create an Abort Message.
84pub fn create_abort_message<P>(setup: &P) -> Vec<u8>
85where
86    P: ProtocolParticipant,
87{
88    SignedMessage::<(), _>::new(
89        &setup.msg_id(None, ABORT_MESSAGE_TAG),
90        setup.message_ttl().as_secs() as _,
91        0,
92        0,
93    )
94    .sign(setup.signer())
95}
96
97/// Returns passed error if msg is a vaild abort message.
98pub fn check_abort<P: ProtocolParticipant, E>(
99    setup: &P,
100    msg: &[u8],
101    party_id: usize,
102    err: impl FnOnce(usize) -> E,
103) -> Result<(), E> {
104    SignedMessage::<(), _>::verify(msg, setup.verifier(party_id))
105        .map_or(Ok(()), |_| Err(err(party_id)))
106}
107
108/// A type with some external represention.
109pub trait Wrap: Sized {
110    /// Size of external representation in bytes
111    fn external_size(&self) -> usize;
112
113    /// Serialize a value into passed buffer
114    fn write(&self, buffer: &mut [u8]);
115
116    /// Deserialize value from given buffer
117    fn read(buffer: &[u8]) -> Option<Self>;
118
119    /// Encode a value into passed buffer and return remaining bytes.
120    fn encode<'a>(&self, buf: &'a mut [u8]) -> &'a mut [u8] {
121        let (buf, rest) = buf.split_at_mut(self.external_size());
122        self.write(buf);
123        rest
124    }
125
126    /// Decode a value from `input` buffer using `size` bytes.
127    /// Return remaining bytes and decoded value.
128    fn decode(input: &[u8], size: usize) -> Option<(&[u8], Self)> {
129        if input.len() < size {
130            return None;
131        }
132        let (input, rest) = input.split_at(size);
133        Some((rest, Self::read(input)?))
134    }
135}
136
137/// A type with fixed size of external representation.
138pub trait FixedExternalSize: Sized {
139    /// Size of an external representation of Self
140    const SIZE: usize;
141}
142
143impl Wrap for () {
144    fn external_size(&self) -> usize {
145        0
146    }
147
148    fn write(&self, _buffer: &mut [u8]) {}
149
150    fn read(_buffer: &[u8]) -> Option<Self> {
151        Some(())
152    }
153}
154
155impl FixedExternalSize for () {
156    const SIZE: usize = 0;
157}
158
159impl<const N: usize> FixedExternalSize for ByteArray<N> {
160    const SIZE: usize = N;
161}
162
163impl<const N: usize> Wrap for ByteArray<N> {
164    fn external_size(&self) -> usize {
165        self.len()
166    }
167
168    fn write(&self, buffer: &mut [u8]) {
169        buffer.copy_from_slice(self);
170    }
171
172    fn read(buffer: &[u8]) -> Option<Self> {
173        let mut value = Self::default();
174        value.copy_from_slice(buffer);
175        Some(value)
176    }
177}
178
179impl Wrap for Scalar {
180    fn external_size(&self) -> usize {
181        mem::size_of::<ScalarBytes>()
182    }
183
184    fn write(&self, buffer: &mut [u8]) {
185        let s = encode_scalar(self);
186        buffer.copy_from_slice(&s);
187    }
188
189    fn read(buffer: &[u8]) -> Option<Self> {
190        decode_scalar(buffer.try_into().ok()?)
191    }
192}
193
194impl Wrap for NonZeroScalar {
195    fn external_size(&self) -> usize {
196        mem::size_of::<ScalarBytes>()
197    }
198
199    fn write(&self, buffer: &mut [u8]) {
200        let s = encode_scalar(self);
201        buffer.copy_from_slice(&s);
202    }
203
204    fn read(buffer: &[u8]) -> Option<Self> {
205        decode_scalar(buffer.try_into().ok()?)
206            .and_then(|s| NonZeroScalar::new(s).into())
207    }
208}
209
210impl Wrap for AffinePoint {
211    fn external_size(&self) -> usize {
212        mem::size_of::<PointBytes>()
213    }
214
215    fn write(&self, buffer: &mut [u8]) {
216        let p = encode_affine(self);
217        buffer.copy_from_slice(&p);
218    }
219
220    fn read(buffer: &[u8]) -> Option<Self> {
221        decode_affine(buffer.try_into().ok()?)
222    }
223}
224
225impl Wrap for ProjectivePoint {
226    fn external_size(&self) -> usize {
227        mem::size_of::<PointBytes>()
228    }
229
230    fn write(&self, buffer: &mut [u8]) {
231        let p = encode_point(self);
232        buffer.copy_from_slice(&p);
233    }
234
235    fn read(buffer: &[u8]) -> Option<Self> {
236        decode_point(buffer.try_into().ok()?)
237    }
238}
239
240impl<const N: usize> Wrap for [u8; N] {
241    fn external_size(&self) -> usize {
242        N
243    }
244
245    fn write(&self, buffer: &mut [u8]) {
246        buffer.copy_from_slice(self);
247    }
248
249    fn read(buffer: &[u8]) -> Option<Self> {
250        let mut value = [0u8; N];
251        value.copy_from_slice(buffer);
252        Some(value)
253    }
254}
255
256impl Wrap for PublicKey {
257    fn external_size(&self) -> usize {
258        32
259    }
260
261    fn write(&self, buffer: &mut [u8]) {
262        buffer.copy_from_slice(self.as_bytes());
263    }
264
265    fn read(buffer: &[u8]) -> Option<Self> {
266        let mut value = [0u8; 32];
267        value.copy_from_slice(buffer);
268        Some(PublicKey::from(value))
269    }
270}
271
272impl Wrap for GroupPolynomial<ProjectivePoint> {
273    fn external_size(&self) -> usize {
274        self.coeffs.len() * mem::size_of::<PointBytes>()
275    }
276
277    fn write(&self, buffer: &mut [u8]) {
278        for (p, b) in self
279            .points()
280            .zip(buffer.chunks_exact_mut(mem::size_of::<PointBytes>()))
281        {
282            b.copy_from_slice(&encode_point(p));
283        }
284    }
285
286    fn read(buffer: &[u8]) -> Option<Self> {
287        buffer
288            .chunks_exact(mem::size_of::<PointBytes>())
289            .map(|p| decode_point(p.try_into().ok()?))
290            .collect::<Option<Vec<ProjectivePoint>>>()
291            .map(GroupPolynomial::new)
292    }
293}
294
295impl FixedExternalSize for DLogProof {
296    const SIZE: usize =
297        mem::size_of::<PointBytes>() + mem::size_of::<ScalarBytes>();
298}
299
300impl Wrap for DLogProof {
301    fn external_size(&self) -> usize {
302        Self::SIZE
303    }
304
305    fn write(&self, buffer: &mut [u8]) {
306        let (t, s) = buffer.split_at_mut(mem::size_of::<PointBytes>());
307
308        self.t.write(t);
309        self.s.write(s);
310    }
311
312    fn read(buffer: &[u8]) -> Option<Self> {
313        let (t, s) = buffer.split_at(mem::size_of::<PointBytes>());
314
315        let t = AffinePoint::read(t)?;
316        let s = Scalar::read(s)?;
317
318        Some(DLogProof { t, s })
319    }
320}
321
322impl Wrap for Vec<u8> {
323    fn external_size(&self) -> usize {
324        self.len()
325    }
326
327    fn write(&self, buffer: &mut [u8]) {
328        buffer.copy_from_slice(self)
329    }
330
331    fn read(buffer: &[u8]) -> Option<Self> {
332        Some(buffer.to_vec())
333    }
334}
335
336impl<T: Wrap + FixedExternalSize> Wrap for Vec<T> {
337    fn external_size(&self) -> usize {
338        self.len() * T::SIZE
339    }
340
341    fn write(&self, buffer: &mut [u8]) {
342        for (v, b) in self.iter().zip(buffer.chunks_exact_mut(T::SIZE)) {
343            v.write(b);
344        }
345    }
346
347    fn read(buffer: &[u8]) -> Option<Self> {
348        buffer
349            .chunks_exact(T::SIZE)
350            .map(T::read)
351            .collect::<Option<Vec<T>>>()
352    }
353}
354
355impl Wrap for u8 {
356    fn external_size(&self) -> usize {
357        1
358    }
359
360    fn write(&self, buffer: &mut [u8]) {
361        buffer[0] = *self;
362    }
363
364    fn read(buffer: &[u8]) -> Option<Self> {
365        buffer.first().copied()
366    }
367}
368
369impl Wrap for u16 {
370    fn external_size(&self) -> usize {
371        2
372    }
373
374    fn write(&self, buffer: &mut [u8]) {
375        buffer[..2].copy_from_slice(&self.to_le_bytes());
376    }
377
378    fn read(buffer: &[u8]) -> Option<Self> {
379        Some(u16::from_le_bytes(buffer.get(..2)?.try_into().unwrap()))
380    }
381}