seedelf_cli/
register.rs

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
161
162
163
164
use crate::schnorr::random_scalar;
use blstrs::{G1Affine, G1Projective, Scalar};
use hex;
use hex::FromHex;
use pallas_primitives::{
    alonzo::{Constr, MaybeIndefArray, PlutusData},
    BoundedBytes, Fragment,
};
use serde::{Deserialize, Serialize};

/// Represents a cryptographic register containing a generator and a public value.
///
/// The `Register` struct holds two points in compressed hex string format:
/// - `generator`: A generator point in G1.
/// - `public_value`: A public value computed as `generator * sk` where `sk` is a scalar.
///
/// It provides methods for creating, serializing, rerandomizing, and verifying ownership of the register.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Hash, Clone, Default)]
pub struct Register {
    pub generator: String,
    pub public_value: String,
}

impl Register {
    /// Creates a new `Register` with the specified generator and public value.
    ///
    /// # Arguments
    ///
    /// * `generator` - A compressed hex string representing the generator point.
    /// * `public_value` - A compressed hex string representing the public value point.
    pub fn new(generator: String, public_value: String) -> Self {
        Self {
            generator,
            public_value,
        }
    }

    /// Generates a `Register` using a provided scalar (`sk`).
    ///
    /// This method decompresses a hardcoded generator point, multiplies it by the scalar
    /// to compute the public value, and compresses both points into hex strings.
    ///
    /// # Arguments
    ///
    /// * `sk` - A scalar used to compute the public value.
    ///
    /// # Returns
    ///
    /// * A new `Register` with compressed generator and public value.
    pub fn create(sk: Scalar) -> Self {
        // Decode and decompress generator
        let compressed_g1_generator: &str = "97F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB";

        let g1_generator: G1Affine = G1Affine::from_compressed(
            &hex::decode(compressed_g1_generator)
                .expect("Failed to decode generator hex")
                .try_into()
                .expect("Invalid generator length"),
        )
        .expect("Failed to decompress generator");

        let public_value: G1Projective = G1Projective::from(g1_generator) * sk;

        // Compress points and return them as hex strings
        Self {
            generator: hex::encode(g1_generator.to_compressed()),
            public_value: hex::encode(public_value.to_compressed()),
        }
    }

    /// Converts the `Register` into a serialized vector of bytes using PlutusData encoding.
    ///
    /// # Returns
    ///
    /// * `Vec<u8>` - A serialized byte vector representing the `Register`.
    ///
    /// # Panics
    ///
    /// * If the generator or public value are invalid hex strings.
    pub fn to_vec(&self) -> Vec<u8> {
        // convert the strings into vectors
        let generator_vector: Vec<u8> = Vec::from_hex(&self.generator).expect("Invalid hex string");
        let public_value_vector: Vec<u8> =
            Vec::from_hex(&self.public_value).expect("Invalid hex string");
        // construct the plutus data
        let plutus_data: PlutusData = PlutusData::Constr(Constr {
            tag: 121,
            any_constructor: None,
            fields: MaybeIndefArray::Indef(vec![
                PlutusData::BoundedBytes(BoundedBytes::from(generator_vector)),
                PlutusData::BoundedBytes(BoundedBytes::from(public_value_vector)),
            ]),
        });
        plutus_data.encode_fragment().unwrap()
    }

    /// Rerandomizes the `Register` using a new random scalar.
    ///
    /// This method multiplies both the generator and the public value by a new random scalar,
    /// producing a rerandomized `Register`.
    ///
    /// # Returns
    ///
    /// * A new `Register` instance with rerandomized points.
    pub fn rerandomize(self) -> Self {
        // Decode and decompress generator
        let g1: G1Affine = G1Affine::from_compressed(
            &hex::decode(self.generator)
                .expect("Failed to decode generator hex")
                .try_into()
                .expect("Invalid generator length"),
        )
        .expect("Failed to decompress generator");

        // Decode and decompress public_value
        let u: G1Affine = G1Affine::from_compressed(
            &hex::decode(self.public_value)
                .expect("Failed to decode public value hex")
                .try_into()
                .expect("Invalid public value length"),
        )
        .expect("Failed to decompress public value");

        // get a random scalar
        let d: Scalar = random_scalar();

        // Multiply points by the scalar in G1Projective
        let g1_randomized: G1Projective = G1Projective::from(g1) * d;
        let u_randomized: G1Projective = G1Projective::from(u) * d;

        // Compress points and return them as hex strings
        Self {
            generator: hex::encode(g1_randomized.to_compressed()),
            public_value: hex::encode(u_randomized.to_compressed()),
        }
    }

    /// Verifies ownership of the `Register` using a provided scalar (`sk`).
    ///
    /// This method checks if the public value in the `Register` matches the generator
    /// multiplied by the scalar.
    ///
    /// # Arguments
    ///
    /// * `sk` - The scalar to verify ownership.
    ///
    /// # Returns
    ///
    /// * `true` - If the scalar matches and proves ownership.
    /// * `false` - Otherwise.
    pub fn is_owned(&self, sk: Scalar) -> bool {
        let g1: G1Affine = G1Affine::from_compressed(
            &hex::decode(&self.generator)
                .expect("Failed to decode generator hex")
                .try_into()
                .expect("Invalid generator length"),
        )
        .expect("Failed to decompress generator");

        let g_x: G1Projective = G1Projective::from(g1) * sk;

        hex::encode(g_x.to_compressed()) == self.public_value
    }
}