07 01 25
вынес константы SHiNe
This commit is contained in:
parent
1c94bb25a6
commit
f1af2bd4d4
@ -26,6 +26,7 @@ dependencies {
|
|||||||
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
|
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
|
||||||
|
|
||||||
|
implementation project(':shine-server-config') // модуль с настройками
|
||||||
implementation project(":shine-server-log") // модуль логирования и уведомления админов
|
implementation project(":shine-server-log") // модуль логирования и уведомления админов
|
||||||
implementation project(':shine-server-db') // модуль для работы с БД содержит и сущности из БД и саму работу с БД
|
implementation project(':shine-server-db') // модуль для работы с БД содержит и сущности из БД и саму работу с БД
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package blockchain;
|
package blockchain;
|
||||||
|
|
||||||
|
import utils.config.ShineSignatureConstants;
|
||||||
import utils.crypto.Ed25519Util;
|
import utils.crypto.Ed25519Util;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -10,13 +11,16 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public final class BchCryptoVerifier {
|
public final class BchCryptoVerifier {
|
||||||
|
|
||||||
private static final byte[] DOMAIN = "SHiNE".getBytes(StandardCharsets.US_ASCII);
|
|
||||||
|
|
||||||
private BchCryptoVerifier() {}
|
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 =
|
* preimage =
|
||||||
* "SHiNE" +
|
* DOMAIN +
|
||||||
* [1] loginLen + loginBytes +
|
* [1] loginLen + loginBytes +
|
||||||
* prevGlobalHash32 +
|
* prevGlobalHash32 +
|
||||||
* prevLineHash32 +
|
* prevLineHash32 +
|
||||||
@ -40,7 +44,7 @@ public final class BchCryptoVerifier {
|
|||||||
throw new IllegalArgumentException("login >255 bytes");
|
throw new IllegalArgumentException("login >255 bytes");
|
||||||
|
|
||||||
ByteBuffer bb = ByteBuffer.allocate(
|
ByteBuffer bb = ByteBuffer.allocate(
|
||||||
DOMAIN.length +
|
DOMAIN_LEN +
|
||||||
1 + loginBytes.length +
|
1 + loginBytes.length +
|
||||||
32 + 32 +
|
32 + 32 +
|
||||||
rawBytes.length
|
rawBytes.length
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package blockchain.body;
|
package blockchain.body;
|
||||||
|
|
||||||
import blockchain.LineIndex;
|
import blockchain.LineIndex;
|
||||||
|
import utils.config.ShineSignatureConstants;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
@ -15,10 +16,8 @@ import java.util.Objects;
|
|||||||
* [2] version=1
|
* [2] version=1
|
||||||
*
|
*
|
||||||
* [2] subType (uint16) = 0
|
* [2] subType (uint16) = 0
|
||||||
* (служебное поле для совместимости с единым форматом body,
|
|
||||||
* чтобы ВСЕ body имели subType одинаковым способом)
|
|
||||||
*
|
*
|
||||||
* [5] tag ASCII "SHiNE"
|
* [TAG_LEN] tag ASCII "SHiNE"
|
||||||
* [1] loginLength=N (uint8)
|
* [1] loginLength=N (uint8)
|
||||||
* [N] login UTF-8
|
* [N] login UTF-8
|
||||||
*
|
*
|
||||||
@ -35,7 +34,12 @@ public final class HeaderBody implements BodyRecord {
|
|||||||
/** Для header всегда 0 (служебная совместимость). */
|
/** Для header всегда 0 (служебная совместимость). */
|
||||||
public static final short SUBTYPE_COMPAT = 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 short subType; // всегда 0
|
||||||
public final String tag; // "SHiNE"
|
public final String tag; // "SHiNE"
|
||||||
@ -57,11 +61,11 @@ public final class HeaderBody implements BodyRecord {
|
|||||||
if (this.subType != SUBTYPE_COMPAT)
|
if (this.subType != SUBTYPE_COMPAT)
|
||||||
throw new IllegalArgumentException("HeaderBody subType must be 0, got=" + (this.subType & 0xFFFF));
|
throw new IllegalArgumentException("HeaderBody subType must be 0, got=" + (this.subType & 0xFFFF));
|
||||||
|
|
||||||
// дальше: tag[5] + loginLen[1] минимум
|
// дальше: tag[TAG_LEN] + loginLen[1] минимум
|
||||||
if (bb.remaining() < 5 + 1)
|
if (bb.remaining() < TAG_LEN + 1)
|
||||||
throw new IllegalArgumentException("Header payload too short");
|
throw new IllegalArgumentException("Header payload too short");
|
||||||
|
|
||||||
byte[] tagBytes = new byte[5];
|
byte[] tagBytes = new byte[TAG_LEN];
|
||||||
bb.get(tagBytes);
|
bb.get(tagBytes);
|
||||||
String t = new String(tagBytes, StandardCharsets.US_ASCII);
|
String t = new String(tagBytes, StandardCharsets.US_ASCII);
|
||||||
if (!TAG.equals(t)) throw new IllegalArgumentException("Bad tag: " + t);
|
if (!TAG.equals(t)) throw new IllegalArgumentException("Bad tag: " + t);
|
||||||
@ -75,7 +79,6 @@ public final class HeaderBody implements BodyRecord {
|
|||||||
bb.get(loginBytes);
|
bb.get(loginBytes);
|
||||||
this.login = new String(loginBytes, StandardCharsets.UTF_8);
|
this.login = new String(loginBytes, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
// запрещаем мусор в конце
|
|
||||||
if (bb.remaining() != 0) {
|
if (bb.remaining() != 0) {
|
||||||
throw new IllegalArgumentException("Unexpected tail bytes, remaining=" + bb.remaining());
|
throw new IllegalArgumentException("Unexpected tail bytes, remaining=" + bb.remaining());
|
||||||
}
|
}
|
||||||
@ -95,7 +98,8 @@ public final class HeaderBody implements BodyRecord {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short expectedLineIndex() {
|
public short expectedLineIndex() {
|
||||||
return LineIndex.HEADER; }
|
return LineIndex.HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HeaderBody check() {
|
public HeaderBody check() {
|
||||||
@ -115,8 +119,8 @@ public final class HeaderBody implements BodyRecord {
|
|||||||
if (loginUtf8.length > 255)
|
if (loginUtf8.length > 255)
|
||||||
throw new IllegalArgumentException("Login too long (>255 bytes)");
|
throw new IllegalArgumentException("Login too long (>255 bytes)");
|
||||||
|
|
||||||
// type[2] + ver[2] + subType[2] + tag[5] + loginLen[1] + login[N]
|
// type[2] + ver[2] + subType[2] + tag[TAG_LEN] + loginLen[1] + login[N]
|
||||||
int cap = 2 + 2 + 2 + 5 + 1 + loginUtf8.length;
|
int cap = 2 + 2 + 2 + TAG_LEN + 1 + loginUtf8.length;
|
||||||
|
|
||||||
ByteBuffer bb = ByteBuffer.allocate(cap).order(ByteOrder.BIG_ENDIAN);
|
ByteBuffer bb = ByteBuffer.allocate(cap).order(ByteOrder.BIG_ENDIAN);
|
||||||
|
|
||||||
@ -125,9 +129,9 @@ public final class HeaderBody implements BodyRecord {
|
|||||||
|
|
||||||
bb.putShort(SUBTYPE_COMPAT);
|
bb.putShort(SUBTYPE_COMPAT);
|
||||||
|
|
||||||
bb.put(TAG.getBytes(StandardCharsets.US_ASCII)); // [5]
|
bb.put(TAG_ASCII); // [TAG_LEN]
|
||||||
bb.put((byte) loginUtf8.length); // [1]
|
bb.put((byte) loginUtf8.length); // [1]
|
||||||
bb.put(loginUtf8); // [N]
|
bb.put(loginUtf8); // [N]
|
||||||
|
|
||||||
return bb.array();
|
return bb.array();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package utils.config;
|
package utils.config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ShineSignatureConstants — строковые префиксы, входящие в подписываемые сообщения.
|
* ShineSignatureConstants — строковые префиксы/домены, входящие в подписываемые сообщения.
|
||||||
*
|
*
|
||||||
* ВАЖНО:
|
* ВАЖНО:
|
||||||
* - префикс добавляется в начало "чтобы подпись нельзя было переиспользовать" между разными типами сообщений.
|
* - префикс добавляется в начало "чтобы подпись нельзя было переиспользовать" между разными типами сообщений.
|
||||||
* - менять префиксы после релиза нельзя, иначе старые подписи перестанут проверяться.
|
* - менять значения после релиза нельзя, иначе старые подписи перестанут проверяться.
|
||||||
*/
|
*/
|
||||||
public final class ShineSignatureConstants {
|
public final class ShineSignatureConstants {
|
||||||
|
|
||||||
@ -13,4 +13,22 @@ public final class ShineSignatureConstants {
|
|||||||
|
|
||||||
/** Подписываемые данные параметра пользователя: prefix + login + param + time_ms + value */
|
/** Подписываемые данные параметра пользователя: prefix + login + param + time_ms + value */
|
||||||
public static final String USER_PARAMETER_PREFIX = "SHiNe/UserParameter:";
|
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;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user