seedelf_cli/
register.rs

1use crate::schnorr::random_scalar;
2use blstrs::{G1Affine, G1Projective, Scalar};
3use hex;
4use hex::FromHex;
5use pallas_primitives::{
6    BoundedBytes, Fragment,
7    alonzo::{Constr, MaybeIndefArray, PlutusData},
8};
9use serde::{Deserialize, Serialize};
10
11/// Represents a cryptographic register containing a generator and a public value.
12///
13/// The `Register` struct holds two points in compressed hex string format:
14/// - `generator`: A generator point in G1.
15/// - `public_value`: A public value computed as `generator * sk` where `sk` is a scalar.
16///
17/// It provides methods for creating, serializing, rerandomizing, and verifying ownership of the register.
18#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Hash, Clone, Default)]
19pub struct Register {
20    pub generator: String,
21    pub public_value: String,
22}
23
24impl Register {
25    /// Creates a new `Register` with the specified generator and public value.
26    ///
27    /// # Arguments
28    ///
29    /// * `generator` - A compressed hex string representing the generator point.
30    /// * `public_value` - A compressed hex string representing the public value point.
31    pub fn new(generator: String, public_value: String) -> Self {
32        Self {
33            generator,
34            public_value,
35        }
36    }
37
38    /// Generates a `Register` using a provided scalar (`sk`).
39    ///
40    /// This method decompresses a hardcoded generator point, multiplies it by the scalar
41    /// to compute the public value, and compresses both points into hex strings.
42    ///
43    /// # Arguments
44    ///
45    /// * `sk` - A scalar used to compute the public value.
46    ///
47    /// # Returns
48    ///
49    /// * A new `Register` with compressed generator and public value.
50    pub fn create(sk: Scalar) -> Self {
51        // Decode and decompress generator
52        let compressed_g1_generator: &str = "97F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB";
53
54        let g1_generator: G1Affine = G1Affine::from_compressed(
55            &hex::decode(compressed_g1_generator)
56                .expect("Failed to decode generator hex")
57                .try_into()
58                .expect("Invalid generator length"),
59        )
60        .expect("Failed to decompress generator");
61
62        let public_value: G1Projective = G1Projective::from(g1_generator) * sk;
63
64        // Compress points and return them as hex strings
65        Self {
66            generator: hex::encode(g1_generator.to_compressed()),
67            public_value: hex::encode(public_value.to_compressed()),
68        }
69    }
70
71    /// Converts the `Register` into a serialized vector of bytes using PlutusData encoding.
72    ///
73    /// # Returns
74    ///
75    /// * `Vec<u8>` - A serialized byte vector representing the `Register`.
76    ///
77    /// # Panics
78    ///
79    /// * If the generator or public value are invalid hex strings.
80    pub fn to_vec(&self) -> Vec<u8> {
81        // convert the strings into vectors
82        let generator_vector: Vec<u8> = Vec::from_hex(&self.generator).expect("Invalid hex string");
83        let public_value_vector: Vec<u8> =
84            Vec::from_hex(&self.public_value).expect("Invalid hex string");
85        // construct the plutus data
86        let plutus_data: PlutusData = PlutusData::Constr(Constr {
87            tag: 121,
88            any_constructor: None,
89            fields: MaybeIndefArray::Indef(vec![
90                PlutusData::BoundedBytes(BoundedBytes::from(generator_vector)),
91                PlutusData::BoundedBytes(BoundedBytes::from(public_value_vector)),
92            ]),
93        });
94        plutus_data.encode_fragment().unwrap()
95    }
96
97    /// Rerandomizes the `Register` using a new random scalar.
98    ///
99    /// This method multiplies both the generator and the public value by a new random scalar,
100    /// producing a rerandomized `Register`.
101    ///
102    /// # Returns
103    ///
104    /// * A new `Register` instance with rerandomized points.
105    pub fn rerandomize(self) -> Self {
106        // Decode and decompress generator
107        let g1: G1Affine = G1Affine::from_compressed(
108            &hex::decode(self.generator)
109                .expect("Failed to decode generator hex")
110                .try_into()
111                .expect("Invalid generator length"),
112        )
113        .expect("Failed to decompress generator");
114
115        // Decode and decompress public_value
116        let u: G1Affine = G1Affine::from_compressed(
117            &hex::decode(self.public_value)
118                .expect("Failed to decode public value hex")
119                .try_into()
120                .expect("Invalid public value length"),
121        )
122        .expect("Failed to decompress public value");
123
124        // get a random scalar
125        let d: Scalar = random_scalar();
126
127        // Multiply points by the scalar in G1Projective
128        let g1_randomized: G1Projective = G1Projective::from(g1) * d;
129        let u_randomized: G1Projective = G1Projective::from(u) * d;
130
131        // Compress points and return them as hex strings
132        Self {
133            generator: hex::encode(g1_randomized.to_compressed()),
134            public_value: hex::encode(u_randomized.to_compressed()),
135        }
136    }
137
138    /// Verifies ownership of the `Register` using a provided scalar (`sk`).
139    ///
140    /// This method checks if the public value in the `Register` matches the generator
141    /// multiplied by the scalar.
142    ///
143    /// # Arguments
144    ///
145    /// * `sk` - The scalar to verify ownership.
146    ///
147    /// # Returns
148    ///
149    /// * `true` - If the scalar matches and proves ownership.
150    /// * `false` - Otherwise.
151    pub fn is_owned(&self, sk: Scalar) -> bool {
152        let g1: G1Affine = G1Affine::from_compressed(
153            &hex::decode(&self.generator)
154                .expect("Failed to decode generator hex")
155                .try_into()
156                .expect("Invalid generator length"),
157        )
158        .expect("Failed to decompress generator");
159
160        let g_x: G1Projective = G1Projective::from(g1) * sk;
161
162        hex::encode(g_x.to_compressed()) == self.public_value
163    }
164}