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
}
}