diff --git a/shine-server-blockchain/build.gradle b/shine-server-blockchain/build.gradle index 6f4eff7..f780efb 100644 --- a/shine-server-blockchain/build.gradle +++ b/shine-server-blockchain/build.gradle @@ -26,6 +26,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0' + implementation project(':shine-server-config') // модуль с настройками implementation project(":shine-server-log") // модуль логирования и уведомления админов implementation project(':shine-server-db') // модуль для работы с БД содержит и сущности из БД и саму работу с БД diff --git a/shine-server-blockchain/src/main/java/blockchain/BchCryptoVerifier.java b/shine-server-blockchain/src/main/java/blockchain/BchCryptoVerifier.java index 6ef1467..f1407b4 100644 --- a/shine-server-blockchain/src/main/java/blockchain/BchCryptoVerifier.java +++ b/shine-server-blockchain/src/main/java/blockchain/BchCryptoVerifier.java @@ -1,5 +1,6 @@ package blockchain; +import utils.config.ShineSignatureConstants; import utils.crypto.Ed25519Util; import java.nio.ByteBuffer; @@ -10,13 +11,16 @@ import java.util.Objects; public final class BchCryptoVerifier { - private static final byte[] DOMAIN = "SHiNE".getBytes(StandardCharsets.US_ASCII); - private BchCryptoVerifier() {} + // ✅ строка — из констант; байты/длина — локально, “на месте” + private static final String DOMAIN_STR = ShineSignatureConstants.BLOCK_HASH_DOMAIN; + private static final byte[] DOMAIN = DOMAIN_STR.getBytes(StandardCharsets.US_ASCII); + private static final int DOMAIN_LEN = DOMAIN.length; + /** * preimage = - * "SHiNE" + + * DOMAIN + * [1] loginLen + loginBytes + * prevGlobalHash32 + * prevLineHash32 + @@ -40,7 +44,7 @@ public final class BchCryptoVerifier { throw new IllegalArgumentException("login >255 bytes"); ByteBuffer bb = ByteBuffer.allocate( - DOMAIN.length + + DOMAIN_LEN + 1 + loginBytes.length + 32 + 32 + rawBytes.length diff --git a/shine-server-blockchain/src/main/java/blockchain/body/HeaderBody.java b/shine-server-blockchain/src/main/java/blockchain/body/HeaderBody.java index 63085c9..28ab2b4 100644 --- a/shine-server-blockchain/src/main/java/blockchain/body/HeaderBody.java +++ b/shine-server-blockchain/src/main/java/blockchain/body/HeaderBody.java @@ -1,6 +1,7 @@ package blockchain.body; import blockchain.LineIndex; +import utils.config.ShineSignatureConstants; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -15,10 +16,8 @@ import java.util.Objects; * [2] version=1 * * [2] subType (uint16) = 0 - * (служебное поле для совместимости с единым форматом body, - * чтобы ВСЕ body имели subType одинаковым способом) * - * [5] tag ASCII "SHiNE" + * [TAG_LEN] tag ASCII "SHiNE" * [1] loginLength=N (uint8) * [N] login UTF-8 * @@ -35,7 +34,12 @@ public final class HeaderBody implements BodyRecord { /** Для header всегда 0 (служебная совместимость). */ public static final short SUBTYPE_COMPAT = 0; - public static final String TAG = "SHiNE"; + /** TAG формата (ASCII). Значение берём из общих строковых констант. */ + public static final String TAG = ShineSignatureConstants.BLOCKCHAIN_HEADER_TAG; + + // ✅ производные значения считаем "на месте", а не в константах + private static final byte[] TAG_ASCII = TAG.getBytes(StandardCharsets.US_ASCII); + private static final int TAG_LEN = TAG_ASCII.length; public final short subType; // всегда 0 public final String tag; // "SHiNE" @@ -57,11 +61,11 @@ public final class HeaderBody implements BodyRecord { if (this.subType != SUBTYPE_COMPAT) throw new IllegalArgumentException("HeaderBody subType must be 0, got=" + (this.subType & 0xFFFF)); - // дальше: tag[5] + loginLen[1] минимум - if (bb.remaining() < 5 + 1) + // дальше: tag[TAG_LEN] + loginLen[1] минимум + if (bb.remaining() < TAG_LEN + 1) throw new IllegalArgumentException("Header payload too short"); - byte[] tagBytes = new byte[5]; + byte[] tagBytes = new byte[TAG_LEN]; bb.get(tagBytes); String t = new String(tagBytes, StandardCharsets.US_ASCII); if (!TAG.equals(t)) throw new IllegalArgumentException("Bad tag: " + t); @@ -75,7 +79,6 @@ public final class HeaderBody implements BodyRecord { bb.get(loginBytes); this.login = new String(loginBytes, StandardCharsets.UTF_8); - // запрещаем мусор в конце if (bb.remaining() != 0) { throw new IllegalArgumentException("Unexpected tail bytes, remaining=" + bb.remaining()); } @@ -95,7 +98,8 @@ public final class HeaderBody implements BodyRecord { @Override public short expectedLineIndex() { - return LineIndex.HEADER; } + return LineIndex.HEADER; + } @Override public HeaderBody check() { @@ -115,8 +119,8 @@ public final class HeaderBody implements BodyRecord { if (loginUtf8.length > 255) throw new IllegalArgumentException("Login too long (>255 bytes)"); - // type[2] + ver[2] + subType[2] + tag[5] + loginLen[1] + login[N] - int cap = 2 + 2 + 2 + 5 + 1 + loginUtf8.length; + // type[2] + ver[2] + subType[2] + tag[TAG_LEN] + loginLen[1] + login[N] + int cap = 2 + 2 + 2 + TAG_LEN + 1 + loginUtf8.length; ByteBuffer bb = ByteBuffer.allocate(cap).order(ByteOrder.BIG_ENDIAN); @@ -125,9 +129,9 @@ public final class HeaderBody implements BodyRecord { bb.putShort(SUBTYPE_COMPAT); - bb.put(TAG.getBytes(StandardCharsets.US_ASCII)); // [5] - bb.put((byte) loginUtf8.length); // [1] - bb.put(loginUtf8); // [N] + bb.put(TAG_ASCII); // [TAG_LEN] + bb.put((byte) loginUtf8.length); // [1] + bb.put(loginUtf8); // [N] return bb.array(); } diff --git a/shine-server-config/src/main/java/utils/config/ShineSignatureConstants.java b/shine-server-config/src/main/java/utils/config/ShineSignatureConstants.java index f90cadd..c3eb190 100644 --- a/shine-server-config/src/main/java/utils/config/ShineSignatureConstants.java +++ b/shine-server-config/src/main/java/utils/config/ShineSignatureConstants.java @@ -1,11 +1,11 @@ package utils.config; /** - * ShineSignatureConstants — строковые префиксы, входящие в подписываемые сообщения. + * ShineSignatureConstants — строковые префиксы/домены, входящие в подписываемые сообщения. * * ВАЖНО: * - префикс добавляется в начало "чтобы подпись нельзя было переиспользовать" между разными типами сообщений. - * - менять префиксы после релиза нельзя, иначе старые подписи перестанут проверяться. + * - менять значения после релиза нельзя, иначе старые подписи перестанут проверяться. */ public final class ShineSignatureConstants { @@ -13,4 +13,22 @@ public final class ShineSignatureConstants { /** Подписываемые данные параметра пользователя: prefix + login + param + time_ms + value */ public static final String USER_PARAMETER_PREFIX = "SHiNe/UserParameter:"; + + /** TAG в HeaderBody (genesis). ASCII "SHiNe". */ + public static final String BLOCKCHAIN_HEADER_TAG = "SHiNe"; + + /** DOMAIN для preimage при расчёте hash32 блока. ASCII "SHiNe". */ + public static final String BLOCK_HASH_DOMAIN = "SHiNe"; + + + // ===================== Фиксированные размеры ===================== + + /** Длина SHA-256 хэша, который хранится в блоке. */ + public static final int HASH32_LEN = 32; + + /** Длина подписи Ed25519, которая хранится в блоке. */ + public static final int SIGNATURE64_LEN = 64; + + /** Длина публичного ключа Ed25519. */ + public static final int ED25519_PUBLIC_KEY32_LEN = 32; } \ No newline at end of file