From e3b37a64d061eabbc4665fc7447e479bd9332721 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Sun, 14 Jan 2024 11:44:17 +0000 Subject: [PATCH] Data: Store compressed KeysAndCert --- core/java/src/net/i2p/data/Destination.java | 16 ++-- core/java/src/net/i2p/data/KeysAndCert.java | 87 ++++++++++++++++++--- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/core/java/src/net/i2p/data/Destination.java b/core/java/src/net/i2p/data/Destination.java index 0df0781e98..6ec59babd9 100644 --- a/core/java/src/net/i2p/data/Destination.java +++ b/core/java/src/net/i2p/data/Destination.java @@ -110,7 +110,7 @@ public class Destination extends KeysAndCert { _publicKey = pk; _signingKey = sk; _certificate = c; - _padding = padding; + setPadding(padding); } /** @@ -122,10 +122,7 @@ public class Destination extends KeysAndCert { int cur = offset; System.arraycopy(_publicKey.getData(), 0, target, cur, PublicKey.KEYSIZE_BYTES); cur += PublicKey.KEYSIZE_BYTES; - if (_padding != null) { - System.arraycopy(_padding, 0, target, cur, _padding.length); - cur += _padding.length; - } + cur = writePaddingBytes(target, cur); int spkTrunc = Math.min(SigningPublicKey.KEYSIZE_BYTES, _signingKey.length()); System.arraycopy(_signingKey.getData(), 0, target, cur, spkTrunc); cur += spkTrunc; @@ -166,8 +163,13 @@ public class Destination extends KeysAndCert { if (_certificate.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) { // cert data included in keys rv += 7; - if (_padding != null) - rv += _padding.length; + if (_paddingBlocks > 1) { + rv += 32 * _paddingBlocks; + } else { + byte[] padding = getPadding(); + if (padding != null) + rv += padding.length; + } } else { rv += _certificate.size(); } diff --git a/core/java/src/net/i2p/data/KeysAndCert.java b/core/java/src/net/i2p/data/KeysAndCert.java index b33cf41a07..70c6760d2a 100644 --- a/core/java/src/net/i2p/data/KeysAndCert.java +++ b/core/java/src/net/i2p/data/KeysAndCert.java @@ -38,7 +38,15 @@ public class KeysAndCert extends DataStructureImpl { protected SigningPublicKey _signingKey; protected Certificate _certificate; private Hash __calculatedHash; - protected byte[] _padding; + // if compressed, 32 bytes only + private byte[] _padding; + /** + * If compressed, the padding size / 32, else 0 + * @since 0.9.62 + */ + protected int _paddingBlocks; + + private static final int PAD_COMP_LEN = 32; public Certificate getCertificate() { return _certificate; @@ -116,10 +124,17 @@ public class KeysAndCert extends DataStructureImpl { } /** + * @return the full padding, expanded if stored compressed * @since 0.9.16 */ public byte[] getPadding() { - return _padding; + if (_paddingBlocks <= 1) + return _padding; + byte[] rv = new byte[PAD_COMP_LEN * _paddingBlocks]; + for (int i = 0; i <_paddingBlocks; i++) { + System.arraycopy(_padding, 0, _paddingBlocks, i * PAD_COMP_LEN, PAD_COMP_LEN); + } + return rv; } /** @@ -130,6 +145,7 @@ public class KeysAndCert extends DataStructureImpl { if (_padding != null) throw new IllegalStateException(); _padding = padding; + compressPadding(); } /** @@ -156,7 +172,7 @@ public class KeysAndCert extends DataStructureImpl { _certificate = cert; } } - + /** * @return null if both are null * @since 0.9.42 @@ -172,15 +188,64 @@ public class KeysAndCert extends DataStructureImpl { return rv; } + /** + * This only does the padding, does not compress the unused 256 byte LS public key. + * Savings is 288 bytes for RI and 64 bytes for LS. + * @since 0.9.62 + */ + private void compressPadding() { + _paddingBlocks = 0; + // > 32 and a mult. of 32 + if (_padding == null || (_padding.length & (2 * PAD_COMP_LEN) - 1) != PAD_COMP_LEN) + return; + int blks = _padding.length / PAD_COMP_LEN; + for (int i = 1; i < blks; i++) { + if (!DataHelper.eq(_padding, 0, _padding, i, PAD_COMP_LEN)) { + return; + } + } + byte[] comp = new byte[PAD_COMP_LEN]; + System.arraycopy(_padding, 0, comp, 0, PAD_COMP_LEN); + _padding = comp; + _paddingBlocks = blks; + } + + /** + * For Destination.writeBytes() + * @return the new offset + * @since 0.9.62 + */ + protected int writePaddingBytes(byte[] target, int off) { + if (_padding == null) + return off; + if (_paddingBlocks > 1) { + for (int i = 0; i < _paddingBlocks; i++) { + System.arraycopy(_padding, 0, target, off, _padding.length); + off += PAD_COMP_LEN; + } + } else { + System.arraycopy(_padding, 0, target, off, _padding.length); + off += _padding.length; + } + return off; + } + public void writeBytes(OutputStream out) throws DataFormatException, IOException { if ((_certificate == null) || (_publicKey == null) || (_signingKey == null)) throw new DataFormatException("Not enough data to format the router identity"); _publicKey.writeBytes(out); - if (_padding != null) - out.write(_padding); - else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES || - _publicKey.length() < PublicKey.KEYSIZE_BYTES) + if (_padding != null) { + if (_paddingBlocks <= 1) { + out.write(_padding); + } else { + for (int i = 0; i <_paddingBlocks; i++) { + out.write(_padding, 0, PAD_COMP_LEN); + } + } + } else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES || + _publicKey.length() < PublicKey.KEYSIZE_BYTES) { throw new DataFormatException("No padding set"); + } _signingKey.writeTruncatedBytes(out); _certificate.writeBytes(out); } @@ -224,8 +289,12 @@ public class KeysAndCert extends DataStructureImpl { buf.append("\n\tPublicKey: ").append(_publicKey); } buf.append("\n\tSigningPublicKey: ").append(_signingKey); - if (_padding != null) - buf.append("\n\tPadding: ").append(_padding.length).append(" bytes"); + if (_padding != null) { + int len = _padding.length; + if (_paddingBlocks > 1) + len *= _paddingBlocks; + buf.append("\n\tPadding: ").append(len).append(" bytes"); + } buf.append(']'); return buf.toString(); } -- GitLab