mpc_stark/algebra/
mod.rs

1//! Defines algebraic MPC types and operations on them
2
3pub mod authenticated_scalar;
4pub mod authenticated_stark_point;
5pub mod macros;
6pub mod mpc_scalar;
7pub mod mpc_stark_point;
8pub mod scalar;
9pub mod stark_curve;
10
11/// Helpers useful for testing throughout the `algebra` module
12#[cfg(test)]
13pub(crate) mod test_helper {
14    use std::iter;
15
16    use super::{scalar::Scalar, stark_curve::StarkPoint};
17
18    use ark_ec::CurveGroup;
19    use ark_ff::PrimeField;
20    use num_bigint::BigUint;
21    use rand::thread_rng;
22    use starknet::core::types::FieldElement as StarknetFelt;
23    use starknet_curve::{AffinePoint, ProjectivePoint};
24
25    // -----------
26    // | Helpers |
27    // -----------
28
29    /// Generate a random point, by multiplying the basepoint with a random scalar
30    pub fn random_point() -> StarkPoint {
31        let mut rng = thread_rng();
32        let scalar = Scalar::random(&mut rng);
33        let point = StarkPoint::generator() * scalar;
34        point * scalar
35    }
36
37    /// Convert a starknet felt to a BigUint
38    pub fn starknet_felt_to_biguint(felt: &StarknetFelt) -> BigUint {
39        BigUint::from_bytes_be(&felt.to_bytes_be())
40    }
41
42    /// Convert a `BigUint` to a starknet felt
43    pub fn biguint_to_starknet_felt(biguint: &BigUint) -> StarknetFelt {
44        // Pad the bytes up to 32 by prepending zeros
45        let bytes = biguint.to_bytes_be();
46        let padded_bytes = iter::repeat(0u8)
47            .take(32 - bytes.len())
48            .chain(bytes.iter().cloned())
49            .collect::<Vec<_>>();
50
51        StarknetFelt::from_bytes_be(&padded_bytes.try_into().unwrap()).unwrap()
52    }
53
54    /// Convert a prime field element to a `BigUint`
55    pub fn prime_field_to_biguint<F: PrimeField>(val: &F) -> BigUint {
56        (*val).into()
57    }
58
59    /// Convert a `Scalar` to a `StarknetFelt`
60    pub fn prime_field_to_starknet_felt<F: PrimeField>(scalar: &F) -> StarknetFelt {
61        biguint_to_starknet_felt(&prime_field_to_biguint(scalar))
62    }
63
64    /// Convert a point in the arkworks representation to a point in the starknet representation
65    pub fn arkworks_point_to_starknet(point: &StarkPoint) -> ProjectivePoint {
66        let affine = point.0.into_affine();
67        let x = prime_field_to_starknet_felt(&affine.x);
68        let y = prime_field_to_starknet_felt(&affine.y);
69
70        ProjectivePoint::from_affine_point(&AffinePoint {
71            x,
72            y,
73            infinity: false,
74        })
75    }
76
77    /// Multiply a point in the starknet-rs `ProjectivePoint` representation with a scalar
78    ///
79    /// Multiplication is only implemented for a point and `&[bool]`, so this method essentially
80    /// provides the bit decomposition  
81    pub fn starknet_rs_scalar_mul(
82        scalar: &StarknetFelt,
83        point: &ProjectivePoint,
84    ) -> ProjectivePoint {
85        let bits = scalar.to_bits_le();
86        point * &bits
87    }
88
89    /// Compare scalars from the two curve implementations
90    pub fn compare_scalars<F: PrimeField>(s1: &F, s2: &StarknetFelt) -> bool {
91        let s1_biguint = prime_field_to_biguint(s1);
92        let s2_biguint = starknet_felt_to_biguint(s2);
93
94        s1_biguint == s2_biguint
95    }
96
97    /// Compare curve points between the two implementation
98    pub fn compare_points(p1: &StarkPoint, p2: &ProjectivePoint) -> bool {
99        // Convert the points to affine coordinates
100        let p1_affine = p1.0.into_affine();
101        let x_1 = p1_affine.x;
102        let y_1 = p1_affine.y;
103
104        let z_inv = p2.z.invert().unwrap();
105        let x_2 = p2.x * z_inv;
106        let y_2 = p2.y * z_inv;
107
108        compare_scalars(&x_1, &x_2) && compare_scalars(&y_1, &y_2)
109    }
110}