arcis_compiler/utils/crypto/
key.rs

1use crate::{
2    core::{
3        circuits::boolean::{
4            boolean_value::{Boolean, BooleanValue},
5            byte::Byte,
6        },
7        expressions::{expr::Expr, other_expr::OtherExpr},
8        global_value::value::FieldValue,
9    },
10    traits::{
11        FromLeBits,
12        FromLeBytes,
13        MxeRescueKey,
14        MxeX25519PrivateKey,
15        Random,
16        Reveal,
17        ToMontgomery,
18    },
19    utils::{
20        curve_point::{Curve, CurvePoint},
21        elliptic_curve::{is_valid_x25519_public_key, AffineEdwardsPoint, F25519},
22        field::{BaseField, ScalarField},
23        matrix::Matrix,
24    },
25    MxeBitInput,
26    MxeInput,
27};
28use std::ops::Mul;
29
30pub const X25519_PRIVATE_KEY_COUNT: usize = 1;
31pub const X25519_PUBLIC_KEY_COUNT: usize = 1;
32pub const X25519_PUBLIC_KEY_BYTES_COUNT: usize = 32;
33pub const RESCUE_KEY_COUNT: usize = 5;
34pub const AES_128_KEY_COUNT: usize = 128;
35pub const AES_192_KEY_COUNT: usize = 192;
36pub const AES_256_KEY_COUNT: usize = 256;
37pub const ED25519_SECRET_KEY_COUNT: usize = 256;
38pub const ED25519_SIGNING_KEY_S_COUNT: usize = 1;
39pub const ED25519_SIGNING_KEY_HASH_PREFIX_COUNT: usize = 256;
40pub const ED25519_VERIFYING_KEY_COUNT: usize = 32;
41pub const ELGAMAL_SECRET_KEY_COUNT: usize = 1;
42pub const ELGAMAL_PUBKEY_COUNT: usize = 1;
43pub const ELGAMAL_PUBKEY_BYTES_COUNT: usize = 32;
44
45/// The Arcis Rescue key type. A key is an array of length 5 of secret-shared
46/// elements over a finite field. The client rescue key is obtained as
47/// key = rescue_prime_hash(get_shared_secret(mxe_x25519_private_key, pubkey)),
48/// while the mxe rescue key corresponds to 5 randomly generated secret-shared
49/// elements of the finite field.
50#[derive(Copy, Clone)]
51pub struct RescueKey<T: Clone + Copy + Random>([T; RESCUE_KEY_COUNT]);
52
53impl<T: Clone + Copy + Random> RescueKey<T> {
54    pub fn new_from_inner(a: [T; RESCUE_KEY_COUNT]) -> Self {
55        Self(a)
56    }
57
58    pub fn inner(&self) -> [T; RESCUE_KEY_COUNT] {
59        self.0
60    }
61
62    /// Loads the MXE Rescue key.
63    pub fn mxe_rescue_key() -> Self
64    where
65        T: MxeRescueKey,
66    {
67        Self(
68            (0..RESCUE_KEY_COUNT)
69                .map(|i| T::mxe_rescue_key(i))
70                .collect::<Vec<T>>()
71                .try_into()
72                .unwrap_or_else(|v: Vec<T>| {
73                    panic!(
74                        "Expected a Vec of length {} (found {})",
75                        RESCUE_KEY_COUNT,
76                        v.len()
77                    )
78                }),
79        )
80    }
81}
82
83impl<T: Clone + Copy + Random> Random for RescueKey<T> {
84    fn random() -> Self {
85        Self(
86            (0..RESCUE_KEY_COUNT)
87                .map(|_| T::random())
88                .collect::<Vec<T>>()
89                .try_into()
90                .unwrap_or_else(|v: Vec<T>| {
91                    panic!(
92                        "Expected a Vec of length {} (found {})",
93                        RESCUE_KEY_COUNT,
94                        v.len()
95                    )
96                }),
97        )
98    }
99}
100
101impl<T: Clone + Copy + Random> From<RescueKey<T>> for Matrix<T> {
102    fn from(key: RescueKey<T>) -> Self {
103        Matrix::from(key.0.to_vec())
104    }
105}
106
107macro_rules! impl_aes_key {
108    ($t: ident, $byte_len:expr, $key_func_trait: ident, $key_func:ident, $mxe_key: ident) => {
109        pub trait $key_func_trait {
110            fn $key_func(i: usize) -> Self;
111        }
112
113        impl $key_func_trait for BooleanValue {
114            fn $key_func(i: usize) -> Self {
115                assert!(i < 8 * $byte_len);
116                Self::from_expr(Expr::Other(OtherExpr::MxeKey(MxeInput::Bit(
117                    MxeBitInput::$t(i),
118                ))))
119            }
120        }
121
122        impl $key_func_trait for bool {
123            fn $key_func(i: usize) -> Self {
124                debug_assert!(i < 8 * $byte_len);
125                ($mxe_key[i / 8] >> (i % 8)) & 1u8 == 1u8
126            }
127        }
128
129        /// The Arcis AES key type.
130        #[derive(Clone, Copy)]
131        pub struct $t<B: Boolean>([Byte<B>; $byte_len]);
132
133        impl<B: Boolean> $t<B> {
134            pub fn new_from_inner(a: [Byte<B>; $byte_len]) -> Self {
135                Self(a)
136            }
137
138            pub fn inner(&self) -> [Byte<B>; $byte_len] {
139                self.0
140            }
141
142            /// Loads the MXE AES key.
143            pub fn mxe_aes_key() -> Self
144            where
145                B: $key_func_trait,
146            {
147                Self(
148                    (0..8 * $byte_len)
149                        .map(|i| B::$key_func(i))
150                        .collect::<Vec<B>>()
151                        .chunks(8)
152                        .map(|chunk| {
153                            Byte::new(chunk.to_vec().try_into().unwrap_or_else(|v: Vec<B>| {
154                                panic!("Expected a Vec of length 8 (found {})", v.len())
155                            }))
156                        })
157                        .collect::<Vec<Byte<B>>>()
158                        .try_into()
159                        .unwrap_or_else(|v: Vec<Byte<B>>| {
160                            panic!("Expected a Vec of length {} (found {})", $byte_len, v.len())
161                        }),
162                )
163            }
164        }
165
166        impl<B: Boolean> Random for $t<B> {
167            fn random() -> Self {
168                Self(
169                    (0..$byte_len)
170                        .map(|_| Byte::<B>::random())
171                        .collect::<Vec<Byte<B>>>()
172                        .try_into()
173                        .unwrap_or_else(|v: Vec<Byte<B>>| {
174                            panic!("Expected a Vec of length {} (found {})", $byte_len, v.len())
175                        }),
176                )
177            }
178        }
179
180        impl $t<BooleanValue> {
181            pub fn compress(&self) -> [FieldValue<BaseField>; ($byte_len as usize).div_ceil(16)] {
182                self.0
183                    .chunks(16)
184                    .map(|bytes| {
185                        FieldValue::<BaseField>::from_le_bits(
186                            bytes
187                                .into_iter()
188                                .flat_map(|byte| byte.to_vec())
189                                .collect::<Vec<BooleanValue>>(),
190                            false,
191                        )
192                    })
193                    .collect::<Vec<FieldValue<BaseField>>>()
194                    .try_into()
195                    .unwrap_or_else(|v: Vec<FieldValue<BaseField>>| {
196                        panic!(
197                            "Expected a Vec of length {} (found {})",
198                            ($byte_len + 15) / 16,
199                            v.len()
200                        )
201                    })
202            }
203        }
204    };
205}
206
207impl_aes_key!(AES128Key, 16, MxeAES128Key, mxe_aes_128_key, MXE_AES128_KEY);
208impl_aes_key!(AES192Key, 24, MxeAES192Key, mxe_aes_192_key, MXE_AES192_KEY);
209impl_aes_key!(AES256Key, 32, MxeAES256Key, mxe_aes_256_key, MXE_AES256_KEY);
210
211/// The Arcis x25519 private key type. A private key is a random element of the
212/// finite field with ell = 2^252 + 27742317777372353535851937790883648493 elements.
213#[derive(Copy, Clone)]
214pub struct X25519PrivateKey<S: Clone + Copy> {
215    key: S,
216    pub is_expected_non_zero: bool,
217}
218
219impl<S: Clone + Copy> X25519PrivateKey<S> {
220    pub fn new(value: S, is_expected_non_zero: bool) -> Self {
221        Self {
222            key: value,
223            is_expected_non_zero,
224        }
225    }
226
227    pub fn inner(&self) -> S {
228        self.key
229    }
230
231    /// Generate a random x25519 private key.
232    /// We generate private keys similar to the standard way of generating a x25519 private key:
233    /// generate 32 random bytes and perform clamped multiplication with the generator/the client's
234    /// pubkey. The reason for doing so is that one generally wants to avoid the expensive check if
235    /// the client pubkey is a valid point of order \ell, and the clamped multiplication
236    /// naturally prevents from small-subgroup attacks. Since we do check on the node that the
237    /// client pubkey is a valid point of order \ell, and input it as a CurveValue, this comes
238    /// down to generating 251 random bits and return \sum_{i=3}^{253} b_i*2^i + 2^254 mod \ell.
239    /// Note: this is by no means better or worse than generating a random ScalarField element,
240    /// it just has become a convention.
241    pub fn random<B: Boolean>() -> Self
242    where
243        S: FromLeBits<B>,
244    {
245        let mut bits = vec![B::from(false); 3];
246        for _ in 0..251 {
247            bits.push(B::random());
248        }
249        bits.push(B::from(true));
250        Self {
251            key: S::from_le_bits(bits, false),
252            is_expected_non_zero: true,
253        }
254    }
255
256    /// Loads the MXE x25519 private key.
257    pub fn mxe_private_key() -> Self
258    where
259        S: MxeX25519PrivateKey,
260    {
261        Self {
262            key: S::mxe_x25519_private_key(),
263            is_expected_non_zero: true,
264        }
265    }
266}
267
268impl<S: Clone + Copy + From<ScalarField>> FromLeBytes for X25519PrivateKey<S> {
269    fn from_le_bytes(bytes: [u8; 32]) -> Self {
270        // clamp the bytes
271        let mut key_bytes = bytes;
272        key_bytes[0] &= 0b1111_1000;
273        key_bytes[31] &= 0b0111_1111;
274        key_bytes[31] |= 0b0100_0000;
275        // Note that the key cannot be zero since the clamped bytes represent a 255-bit
276        // multiple of 8 and the lcm of 8 and \ell is 8 * \ell, which is 256 bits long.
277        X25519PrivateKey::new(
278            S::from(ScalarField::from_le_bits(
279                key_bytes
280                    .into_iter()
281                    .flat_map(|byte| Byte::from(byte).to_vec())
282                    .collect::<Vec<bool>>(),
283                false,
284            )),
285            true,
286        )
287    }
288}
289
290impl Default for X25519PrivateKey<ScalarField> {
291    fn default() -> Self {
292        Self::from_le_bytes([0u8; 32])
293    }
294}
295
296/// The Arcis x25519 public key type.
297/// A public key is not necessarily public.
298#[derive(Copy, Clone)]
299pub struct X25519PublicKey<C: Curve> {
300    point: C,
301    pub is_expected_non_identity: bool,
302}
303
304impl<C: Curve> X25519PublicKey<C> {
305    pub fn new(value: C, is_expected_non_identity: bool) -> Self {
306        Self {
307            point: value,
308            is_expected_non_identity,
309        }
310    }
311
312    pub fn new_from_private_key<S: Clone + Copy + Mul<C, Output = C>>(
313        private_key: X25519PrivateKey<S>,
314    ) -> Self {
315        Self {
316            point: private_key.inner() * C::generator(),
317            is_expected_non_identity: private_key.is_expected_non_zero,
318        }
319    }
320
321    pub fn inner(&self) -> C {
322        self.point
323    }
324
325    pub fn to_montgomery<Base: F25519>(self) -> (Base, Base)
326    where
327        C: ToMontgomery<Output = Base>,
328    {
329        self.point.to_montgomery(self.is_expected_non_identity)
330    }
331}
332
333impl X25519PublicKey<CurvePoint> {
334    /// A X25519PublicKey is serialized by converting the inner CurvePoint to Montgomery coordinates
335    /// and then serializing the u-coordinate (a BaseField element).
336    pub fn to_le_bytes(&self) -> [u8; 32] {
337        self.to_montgomery().0.to_le_bytes().map(u8::from)
338    }
339
340    /// Given the serialized Montgomery u-coordinate of a x25519 pubkey, checks the validity of the
341    /// bytes and constructs a X25519PublicKey.
342    pub fn from_le_bytes(bytes: [u8; 32]) -> Option<Self> {
343        is_valid_x25519_public_key(bytes).map(|montgomery_point| {
344            // convert the affine Montgomery point to a CurvePoint
345            let edwards_point = AffineEdwardsPoint::from_montgomery(montgomery_point);
346            Self {
347                point: CurvePoint::from(edwards_point),
348                is_expected_non_identity: true,
349            }
350        })
351    }
352}
353
354impl<C: Curve> Reveal for X25519PublicKey<C> {
355    fn reveal(self) -> Self {
356        Self {
357            point: self.point.reveal(),
358            is_expected_non_identity: self.is_expected_non_identity,
359        }
360    }
361}
362
363impl Default for X25519PublicKey<CurvePoint> {
364    fn default() -> Self {
365        Self::new_from_private_key(X25519PrivateKey::<ScalarField>::default())
366    }
367}
368
369// Randomly generated element of the scalar field.
370pub(crate) const MXE_X25519_PRIVATE_KEY: [u8; 32] = [
371    207, 40, 181, 230, 45, 204, 46, 17, 8, 19, 251, 241, 43, 129, 216, 23, 86, 169, 218, 248, 95,
372    114, 111, 9, 188, 159, 223, 16, 124, 98, 41, 1,
373];
374
375// Five randomly generated elements of the base field.
376pub(crate) const MXE_RESCUE_BASE_FIELD_KEY: [[u8; 32]; 5] = [
377    [
378        124, 219, 118, 100, 151, 174, 173, 201, 180, 159, 95, 202, 109, 154, 90, 104, 99, 221, 206,
379        79, 44, 221, 182, 198, 143, 180, 180, 121, 78, 223, 238, 12,
380    ],
381    [
382        158, 10, 32, 122, 234, 85, 113, 2, 69, 115, 151, 149, 163, 189, 216, 108, 160, 21, 118,
383        154, 185, 199, 198, 251, 142, 193, 168, 98, 218, 59, 20, 9,
384    ],
385    [
386        45, 115, 67, 23, 196, 46, 150, 202, 33, 22, 44, 144, 204, 34, 166, 30, 183, 63, 38, 213,
387        166, 150, 234, 191, 201, 13, 79, 86, 171, 100, 140, 15,
388    ],
389    [
390        209, 1, 108, 251, 175, 105, 199, 246, 83, 186, 72, 0, 15, 236, 105, 110, 5, 109, 41, 216,
391        148, 98, 208, 128, 32, 47, 224, 93, 90, 176, 33, 2,
392    ],
393    [
394        179, 142, 132, 221, 113, 147, 206, 83, 22, 121, 245, 155, 239, 204, 18, 158, 119, 190, 54,
395        17, 28, 17, 247, 191, 151, 147, 118, 151, 38, 169, 21, 4,
396    ],
397];
398
399// Five randomly generated elements of the scalar field.
400pub(crate) const MXE_RESCUE_SCALAR_FIELD_KEY: [[u8; 32]; 5] = [
401    [
402        72, 239, 104, 144, 184, 215, 25, 76, 171, 209, 107, 34, 146, 39, 35, 134, 103, 10, 38, 148,
403        251, 155, 69, 207, 216, 234, 104, 220, 253, 63, 217, 14,
404    ],
405    [
406        11, 232, 48, 222, 61, 142, 29, 189, 73, 204, 120, 1, 111, 20, 233, 1, 101, 49, 169, 220,
407        66, 250, 21, 125, 132, 247, 11, 21, 128, 217, 231, 12,
408    ],
409    [
410        33, 164, 174, 155, 214, 77, 209, 93, 24, 230, 196, 38, 29, 5, 89, 76, 52, 85, 219, 66, 90,
411        7, 190, 27, 181, 51, 206, 187, 99, 72, 251, 2,
412    ],
413    [
414        7, 178, 214, 42, 8, 10, 134, 249, 244, 69, 192, 63, 96, 204, 229, 10, 126, 3, 33, 49, 174,
415        26, 149, 5, 254, 118, 230, 75, 149, 105, 145, 5,
416    ],
417    [
418        22, 94, 36, 119, 174, 65, 70, 75, 230, 11, 102, 41, 31, 194, 55, 255, 24, 25, 113, 181,
419        206, 213, 243, 203, 115, 152, 90, 177, 232, 228, 145, 3,
420    ],
421];
422
423// 16 randomly generated bytes.
424pub(crate) const MXE_AES128_KEY: [u8; 16] = [
425    124, 219, 118, 100, 151, 174, 173, 201, 180, 159, 95, 202, 109, 154, 90, 104,
426];
427
428// 24 randomly generated bytes.
429pub(crate) const MXE_AES192_KEY: [u8; 24] = [
430    159, 234, 203, 164, 191, 151, 2, 150, 165, 97, 217, 48, 4, 227, 91, 13, 244, 2, 222, 234, 226,
431    187, 253, 127,
432];
433
434// 32 randomly generated bytes.
435pub(crate) const MXE_AES256_KEY: [u8; 32] = [
436    196, 120, 191, 34, 144, 89, 36, 185, 242, 159, 162, 158, 170, 37, 234, 191, 33, 141, 52, 147,
437    253, 3, 58, 49, 169, 146, 53, 185, 1, 55, 60, 87,
438];
439
440// 32 randomly generated bytes.
441pub(crate) const MXE_ED25519_SECRET_KEY: [u8; 32] = [
442    13, 192, 52, 244, 242, 224, 239, 161, 194, 4, 155, 74, 60, 148, 207, 43, 188, 194, 251, 154,
443    142, 189, 227, 93, 25, 249, 65, 205, 121, 53, 203, 22,
444];
445
446// Signing key s derived from MXE_ED25519_SECRET_KEY.
447pub(crate) const MXE_ED25519_SIGNING_KEY_S: [u8; 32] = [
448    60, 248, 182, 157, 91, 202, 9, 247, 187, 176, 179, 140, 115, 51, 98, 253, 44, 82, 56, 212, 19,
449    155, 154, 68, 254, 17, 132, 223, 74, 130, 165, 12,
450];
451
452// Signing key hash-prefix derived from MXE_ED25519_SECRET_KEY.
453pub(crate) const MXE_ED25519_SIGNING_KEY_HASH_PREFIX: [u8; 32] = [
454    217, 141, 36, 192, 41, 135, 248, 83, 212, 208, 84, 27, 188, 50, 69, 245, 68, 207, 121, 207, 6,
455    115, 30, 27, 94, 187, 91, 113, 18, 219, 27, 64,
456];
457
458// Verifying key derived from MXE_ED25519_SECRET_KEY.
459pub(crate) const MXE_ED25519_VERIFYING_KEY: [u8; 32] = [
460    14, 32, 126, 133, 202, 216, 28, 182, 228, 95, 141, 94, 34, 155, 36, 238, 53, 102, 82, 241, 81,
461    180, 136, 239, 169, 22, 226, 133, 195, 171, 252, 7,
462];
463
464// Randomly generated element of the scalar field.
465pub(crate) const MXE_ELGAMAL_SECRET_KEY: [u8; 32] = [
466    57, 71, 187, 92, 7, 239, 222, 40, 252, 52, 135, 191, 198, 199, 173, 77, 31, 119, 254, 244, 152,
467    71, 131, 255, 183, 183, 182, 191, 87, 99, 182, 3,
468];
469
470// Public key derived from MXE_ELGAMAL_SECRET_KEY, stored as CompressedRistretto.
471pub(crate) const MXE_ELGAMAL_PUBKEY: [u8; 32] = [
472    168, 163, 137, 87, 0, 80, 192, 23, 16, 133, 172, 238, 187, 164, 133, 148, 115, 126, 183, 16,
473    220, 95, 125, 82, 16, 175, 99, 114, 226, 131, 197, 111,
474];