Skip to content

Commit

Permalink
Add BlsPublicKey::trusted_{deserialize,serialize}
Browse files Browse the repository at this point in the history
  • Loading branch information
hrxi committed Feb 6, 2025
1 parent b5efac0 commit 9041928
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 16 deletions.
40 changes: 38 additions & 2 deletions bls/src/types/public_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub struct PublicKey {
}

impl PublicKey {
/// Size of the trusted serialization.
///
/// See [`PublicKey::trusted_deserialize`].
pub const TRUSTED_SERIALIZATION_SIZE: usize = 570;

/// Generates a public key from a given point in G2. This function will produce an error if it is given the point at infinity.
Expand Down Expand Up @@ -62,8 +65,9 @@ impl PublicKey {
/// and one bit indicating if it is the "point-at-infinity".
pub fn compress(&self) -> CompressedPublicKey {
let mut buffer = [0u8; CompressedPublicKey::SIZE];
CanonicalSerialize::serialize_compressed(&self.public_key.into_affine(), &mut buffer[..])
.unwrap();
let affine = self.public_key.into_affine();
assert_eq!(affine.compressed_size(), buffer.len());
affine.serialize_compressed(&mut buffer[..]).unwrap();
CompressedPublicKey { public_key: buffer }
}

Expand All @@ -74,6 +78,38 @@ impl PublicKey {
let public_key = self.public_key.mul_bigint([x as u64]);
PublicKey { public_key }
}

/// Serialization to trusted storage.
///
/// If in doubt, use the default serialization, or even better, the default
/// serialization of [`LazyPublicKey`](crate::lazy::LazyPublicKey) instead.
///
/// See [`PublicKey::trusted_deserialize`] for details.
pub fn trusted_serialize(&self) -> [u8; PublicKey::TRUSTED_SERIALIZATION_SIZE] {
let mut result = [0u8; PublicKey::TRUSTED_SERIALIZATION_SIZE];
assert_eq!(self.public_key.uncompressed_size(), result.len());
self.public_key
.serialize_uncompressed(&mut result[..])
.unwrap();
result
}

/// Deserialization from trusted storage.
///
/// **This does not check whether the resulting key is on the curve.** This
/// means that you can only use this serialization when you trust the
/// creator of that serialization completely.
///
/// If in doubt, use the default serialization, or even better, the default
/// serialization of [`LazyPublicKey`](crate::lazy::LazyPublicKey) instead.
pub fn trusted_deserialize(
serialized: &[u8; PublicKey::TRUSTED_SERIALIZATION_SIZE],
) -> PublicKey {
PublicKey {
public_key: CanonicalDeserialize::deserialize_uncompressed_unchecked(&serialized[..])
.unwrap(),
}
}
}

impl Eq for PublicKey {}
Expand Down
14 changes: 14 additions & 0 deletions bls/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,17 @@ fn aggregate_signatures_serialization() {
&AggregateSignature::deserialize_from_vec(&ser_agg_sig).unwrap()
));
}

#[test]
fn trusted_serialization() {
let hex_public_key = "ae4cc2e31e04add9a6d379b4379b02f302971503cbac8d02fdc5d2dc8204d24ec8d095627d037de747f1a8ea7bf3c1693262d947f78e0cc73c18ecc2f2ec5b2249d551e1680fe0c973a7951bd78d4fbe0326be71286ed34004d2443eb3b00167a02edffcfd2b8539448fa116c5454da2d181dc03ea8cfe3fedb58b9b945d5e506c794deb3ba73983005b3ff799212bf59030a8dd17ff48fd5d015695195a022fed8ba4fab28a4c3e2d6f41be0e6315e41824df161219c02be5a281c215011c13131184187e9100d2d6a5321fd9b154806ecc78e93b91331a5334b8876fd1b8ea62b17ce6045fc9e1af60b7705b0cf86dba79f5bcb8320c99a45f3b7c7178f8f87ba953de2755c61af882059c1de1d7a35357f06cd4a7d954e4bb211900";

let raw_public_key: Vec<u8> = hex::decode(hex_public_key).unwrap();
let compressed_public_key = CompressedPublicKey::deserialize_from_vec(&raw_public_key).unwrap();

let public_key = compressed_public_key.uncompress().unwrap();
assert_eq!(
PublicKey::trusted_deserialize(&public_key.trusted_serialize()).public_key,
public_key.public_key,
);
}
23 changes: 9 additions & 14 deletions web-client/src/client/bls_cache.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress};
use idb::{Database, Error, KeyPath, ObjectStore, TransactionMode};
use nimiq_bls::{G2Projective, LazyPublicKey, PublicKey};
use nimiq_bls::{LazyPublicKey, PublicKey};
use nimiq_serde::{Deserialize, Serialize};

/// Caches decompressed BlsPublicKeys in an IndexedDB
Expand All @@ -12,7 +11,7 @@ pub(crate) struct BlsCache {
#[derive(Deserialize, Serialize)]
struct BlsKeyEntry {
#[serde(with = "serde_bytes")]
public_key: Vec<u8>,
public_key: [u8; PublicKey::TRUSTED_SERIALIZATION_SIZE],
}

const BLS_KEYS: &str = "bls_keys";
Expand Down Expand Up @@ -49,15 +48,13 @@ impl BlsCache {
let bls_keys_store = transaction.object_store(BLS_KEYS)?;

for key in keys {
let mut public_key = Vec::new();
assert!(key.has_uncompressed());
key.uncompress()
.expect("must not pass invalid keys to `BlsCache::add_keys`")
.public_key
.serialize_with_mode(&mut public_key, Compress::No)
.unwrap();

let entry = BlsKeyEntry { public_key };
let entry = BlsKeyEntry {
public_key: key
.uncompress()
.expect("must not pass invalid keys to `BlsCache::add_keys`")
.trusted_serialize(),
};
let entry_js_value = serde_wasm_bindgen::to_value(&entry).unwrap();
bls_keys_store.put(&entry_js_value, None)?.await?;
}
Expand All @@ -79,9 +76,7 @@ impl BlsCache {

for js_key in &js_keys {
let value: BlsKeyEntry = serde_wasm_bindgen::from_value(js_key.clone()).unwrap();
let public_key = PublicKey::new(
G2Projective::deserialize_uncompressed_unchecked(&*value.public_key).unwrap(),
);
let public_key = PublicKey::trusted_deserialize(&value.public_key);
self.keys.push(LazyPublicKey::from(public_key));
}
transaction.await?;
Expand Down

0 comments on commit 9041928

Please sign in to comment.