Skip to content

Commit 9679168

Browse files
committed
feat CRP-2787 Add IBE ciphertext size helper functions
1 parent dc40657 commit 9679168

File tree

6 files changed

+71
-7
lines changed

6 files changed

+71
-7
lines changed

backend/rs/ic_vetkeys/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Added MasterPublicKey::production_key which allows accessing the production public keys
88

9+
- Added IbeCiphertext plaintextSize and ciphertextSize helpers
10+
911
## [0.3.0] - 2025-06-30
1012

1113
### Added

backend/rs/ic_vetkeys/src/utils/mod.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,8 @@ const IBE_HEADER: [u8; 8] = [b'I', b'C', b' ', b'I', b'B', b'E', 0x00, 0x01];
564564

565565
const IBE_HEADER_BYTES: usize = IBE_HEADER.len();
566566

567+
const IBE_OVERHEAD: usize = IBE_HEADER_BYTES + IBE_SEED_BYTES + G2AFFINE_BYTES;
568+
567569
#[derive(Clone, Debug, Eq, PartialEq)]
568570
/// An IBE (identity based encryption) ciphertext
569571
pub struct IbeCiphertext {
@@ -599,8 +601,7 @@ impl IbeDomainSep {
599601
impl IbeCiphertext {
600602
/// Serialize this IBE ciphertext
601603
pub fn serialize(&self) -> Vec<u8> {
602-
let mut output =
603-
Vec::with_capacity(self.header.len() + G2AFFINE_BYTES + IBE_SEED_BYTES + self.c3.len());
604+
let mut output = Vec::with_capacity(IBE_OVERHEAD + self.c3.len());
604605

605606
output.extend_from_slice(&self.header);
606607
output.extend_from_slice(&self.c1.to_compressed());
@@ -614,7 +615,7 @@ impl IbeCiphertext {
614615
///
615616
/// Returns Err if the encoding is not valid
616617
pub fn deserialize(bytes: &[u8]) -> Result<Self, String> {
617-
if bytes.len() < IBE_HEADER_BYTES + G2AFFINE_BYTES + IBE_SEED_BYTES {
618+
if bytes.len() < IBE_OVERHEAD {
618619
return Err("IbeCiphertext too short to be valid".to_string());
619620
}
620621

@@ -637,7 +638,6 @@ impl IbeCiphertext {
637638
}
638639

639640
fn hash_to_mask(header: &[u8], seed: &[u8; IBE_SEED_BYTES], msg: &[u8]) -> Scalar {
640-
641641
/*
642642
It would have been better to instead use the SHA-256 of the message instead of the
643643
message directly, since that would avoid having to allocate an extra buffer of
@@ -763,6 +763,23 @@ impl IbeCiphertext {
763763
Err("decryption failed".to_string())
764764
}
765765
}
766+
767+
/// Helper function for determining size of the IBE ciphertext
768+
pub fn ciphertext_size(ptext_len: usize) -> usize {
769+
return ptext_len + IBE_OVERHEAD;
770+
}
771+
772+
/// Helper function for determining size of the IBE plaintext
773+
///
774+
/// Returns Err if the indicated ctext_len would be a ciphertext
775+
/// that is not possibly valid (due to missing required elements)
776+
pub fn plaintext_size(ctext_len: usize) -> Result<usize, ()> {
777+
if ctext_len < IBE_OVERHEAD {
778+
return Err(());
779+
} else {
780+
return Ok(ctext_len - IBE_OVERHEAD);
781+
}
782+
}
766783
}
767784

768785
/// Verify an augmented BLS signature

backend/rs/ic_vetkeys/tests/utils.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
use hex_literal::hex;
12
use ic_bls12_381::*;
23
use ic_vetkeys::*;
34
use ic_vetkeys_test_utils::*;
45
use rand::Rng;
5-
use hex_literal::hex;
66

77
#[test]
88
fn test_hkdf_test_vector() {
@@ -28,7 +28,10 @@ fn test_hkdf_test_vector() {
2828

2929
#[test]
3030
fn test_is_valid_transport_public_key() {
31-
assert_eq!(is_valid_transport_public_key_encoding(&hex::decode("F00F00F00F00").unwrap()), false);
31+
assert_eq!(
32+
is_valid_transport_public_key_encoding(&hex::decode("F00F00F00F00").unwrap()),
33+
false
34+
);
3235
assert_eq!(is_valid_transport_public_key_encoding(&hex::decode("97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb").unwrap()), true);
3336
assert_eq!(is_valid_transport_public_key_encoding(&hex::decode("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()), true);
3437
}
@@ -68,7 +71,8 @@ fn test_bls_signature_verification() {
6871
fn test_bls_signature_verification_using_identity() {
6972
// Check that the identity element is rejected as a public key
7073

71-
let dpk = DerivedPublicKey::deserialize(&ic_bls12_381::G2Affine::identity().to_compressed()).unwrap();
74+
let dpk =
75+
DerivedPublicKey::deserialize(&ic_bls12_381::G2Affine::identity().to_compressed()).unwrap();
7276

7377
let msg = b"wrong message";
7478

frontend/ic_vetkeys/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Added MasterPublicKey.productionKey which allows accessing the production public keys
88

9+
- Added IbeCiphertext plaintextSize and ciphertextSize helpers
10+
911
## [0.3.0] - 2025-06-30
1012

1113
### Changed

frontend/ic_vetkeys/src/utils/utils.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,14 @@ test("AES-GCM encryption", async () => {
380380
}
381381
});
382382

383+
test("IBE ciphertext size utils", () => {
384+
for (let ptextLen: number = 0; ptextLen != 1024; ++ptextLen) {
385+
let ctextLen = IbeCiphertext.ciphertextSize(ptextLen);
386+
let recPtextLen = IbeCiphertext.plaintextSize(ctextLen);
387+
assertEqual(ptextLen, recPtextLen);
388+
}
389+
});
390+
383391
test("hkdf test vectors", () => {
384392
// HKDF test vectors from wycheproof
385393
const testVectors = [

frontend/ic_vetkeys/src/utils/utils.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,11 @@ export class IbeSeed {
928928
}
929929
}
930930

931+
/**
932+
* Total overhead for an IBE ciphertext
933+
*/
934+
const IBE_OVERHEAD = IBE_HEADER_LEN + IBE_SEED_BYTES + G2_BYTES;
935+
931936
/**
932937
* IBE (Identity Based Encryption)
933938
*/
@@ -937,6 +942,32 @@ export class IbeCiphertext {
937942
readonly #c2: Uint8Array;
938943
readonly #c3: Uint8Array;
939944

945+
/**
946+
* Helper function for determining size of the IBE ciphertext
947+
*/
948+
static ciphertextSize(plaintextSize: number): number {
949+
if (plaintextSize < 0) {
950+
throw new Error(
951+
"IbeCiphertext.ciphertextSize argument cannot be negative",
952+
);
953+
}
954+
955+
return plaintextSize + IBE_OVERHEAD;
956+
}
957+
958+
/**
959+
* Helper function for determining size of the IBE plaintext
960+
*/
961+
static plaintextSize(ciphertextSize: number): number {
962+
if (ciphertextSize < IBE_OVERHEAD) {
963+
throw new Error(
964+
"IbeCiphertext.plaintextSize given ciphertext size is too small to be valid",
965+
);
966+
}
967+
968+
return ciphertextSize - IBE_OVERHEAD;
969+
}
970+
940971
/**
941972
* Serialize the IBE ciphertext to a bytestring
942973
*/

0 commit comments

Comments
 (0)