SHA256
16 12 25
Промежуточная версия и ТУДУ на чём остановился
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
package blockchain_new;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* BchBlockEntry_new — универсальный блок нового формата.
|
||||
*
|
||||
* RAW (BigEndian):
|
||||
* [4] recordSize (int) = RAW + signature + hash
|
||||
* [4] recordNumber (int) глобальный номер блока
|
||||
* [8] timestamp (long) unix seconds
|
||||
* [2] line (short)
|
||||
* [4] lineNumber (int)
|
||||
* [N] bodyBytes (body, начинается с [type][version])
|
||||
*
|
||||
* TAIL:
|
||||
* [64] signature64 (Ed25519)
|
||||
* [32] hash32 (SHA-256)
|
||||
*/
|
||||
public final class BchBlockEntry_new {
|
||||
|
||||
public static final int SIGNATURE_LEN = 64;
|
||||
public static final int HASH_LEN = 32;
|
||||
|
||||
/** Размер фиксированного RAW-заголовка без body */
|
||||
public static final int RAW_HEADER_SIZE = 4 + 4 + 8 + 2 + 4;
|
||||
|
||||
// --- RAW ---
|
||||
public final int recordSize;
|
||||
public final int recordNumber;
|
||||
public final long timestamp;
|
||||
public final short line;
|
||||
public final int lineNumber;
|
||||
public final byte[] bodyBytes;
|
||||
|
||||
// --- TAIL ---
|
||||
private final byte[] signature64;
|
||||
private final byte[] hash32;
|
||||
|
||||
// --- cached ---
|
||||
private final byte[] fullBytes;
|
||||
|
||||
/* ===================================================================== */
|
||||
/* ====================== Конструктор из байт ========================== */
|
||||
/* ===================================================================== */
|
||||
|
||||
public BchBlockEntry_new(byte[] fullBytes) {
|
||||
Objects.requireNonNull(fullBytes, "fullBytes == null");
|
||||
if (fullBytes.length < RAW_HEADER_SIZE + SIGNATURE_LEN + HASH_LEN)
|
||||
throw new IllegalArgumentException("Block too short");
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(fullBytes).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
this.recordSize = bb.getInt();
|
||||
if (recordSize != fullBytes.length)
|
||||
throw new IllegalArgumentException("recordSize mismatch");
|
||||
|
||||
this.recordNumber = bb.getInt();
|
||||
this.timestamp = bb.getLong();
|
||||
this.line = bb.getShort();
|
||||
this.lineNumber = bb.getInt();
|
||||
|
||||
int bodyLen = recordSize - RAW_HEADER_SIZE - SIGNATURE_LEN - HASH_LEN;
|
||||
if (bodyLen <= 0)
|
||||
throw new IllegalArgumentException("Invalid body length");
|
||||
|
||||
this.bodyBytes = new byte[bodyLen];
|
||||
bb.get(this.bodyBytes);
|
||||
|
||||
this.signature64 = new byte[SIGNATURE_LEN];
|
||||
bb.get(this.signature64);
|
||||
|
||||
this.hash32 = new byte[HASH_LEN];
|
||||
bb.get(this.hash32);
|
||||
|
||||
this.fullBytes = Arrays.copyOf(fullBytes, fullBytes.length);
|
||||
}
|
||||
|
||||
/* ===================================================================== */
|
||||
/* ====================== Конструктор сборки ============================ */
|
||||
/* ===================================================================== */
|
||||
|
||||
public BchBlockEntry_new(int recordNumber,
|
||||
long timestamp,
|
||||
short line,
|
||||
int lineNumber,
|
||||
byte[] bodyBytes,
|
||||
byte[] signature64,
|
||||
byte[] hash32) {
|
||||
|
||||
Objects.requireNonNull(bodyBytes, "bodyBytes == null");
|
||||
Objects.requireNonNull(signature64, "signature64 == null");
|
||||
Objects.requireNonNull(hash32, "hash32 == null");
|
||||
|
||||
if (signature64.length != SIGNATURE_LEN)
|
||||
throw new IllegalArgumentException("signature64 != 64");
|
||||
if (hash32.length != HASH_LEN)
|
||||
throw new IllegalArgumentException("hash32 != 32");
|
||||
|
||||
this.recordNumber = recordNumber;
|
||||
this.timestamp = timestamp;
|
||||
this.line = line;
|
||||
this.lineNumber = lineNumber;
|
||||
this.bodyBytes = Arrays.copyOf(bodyBytes, bodyBytes.length);
|
||||
this.signature64 = Arrays.copyOf(signature64, SIGNATURE_LEN);
|
||||
this.hash32 = Arrays.copyOf(hash32, HASH_LEN);
|
||||
|
||||
this.recordSize =
|
||||
RAW_HEADER_SIZE +
|
||||
bodyBytes.length +
|
||||
SIGNATURE_LEN +
|
||||
HASH_LEN;
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(recordSize).order(ByteOrder.BIG_ENDIAN);
|
||||
bb.putInt(recordSize);
|
||||
bb.putInt(recordNumber);
|
||||
bb.putLong(timestamp);
|
||||
bb.putShort(line);
|
||||
bb.putInt(lineNumber);
|
||||
bb.put(bodyBytes);
|
||||
bb.put(this.signature64);
|
||||
bb.put(this.hash32);
|
||||
|
||||
this.fullBytes = bb.array();
|
||||
}
|
||||
|
||||
/* ===================================================================== */
|
||||
|
||||
public byte[] getSignature64() {
|
||||
return Arrays.copyOf(signature64, SIGNATURE_LEN);
|
||||
}
|
||||
|
||||
public byte[] getHash32() {
|
||||
return Arrays.copyOf(hash32, HASH_LEN);
|
||||
}
|
||||
|
||||
public byte[] toBytes() {
|
||||
return Arrays.copyOf(fullBytes, fullBytes.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package blockchain_new;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class BchCryptoVerifier_new {
|
||||
|
||||
private static final byte[] DOMAIN = "SHiNE".getBytes(StandardCharsets.US_ASCII);
|
||||
|
||||
private BchCryptoVerifier_new() {}
|
||||
|
||||
/**
|
||||
* preimage =
|
||||
* "SHiNE" +
|
||||
* [1] loginLen + loginBytes +
|
||||
* prevGlobalHash32 +
|
||||
* prevLineHash32 +
|
||||
* rawBytes
|
||||
*/
|
||||
public static byte[] buildPreimage(String userLogin,
|
||||
byte[] prevGlobalHash32,
|
||||
byte[] prevLineHash32,
|
||||
byte[] rawBytes) {
|
||||
|
||||
Objects.requireNonNull(userLogin, "userLogin == null");
|
||||
Objects.requireNonNull(prevGlobalHash32, "prevGlobalHash32 == null");
|
||||
Objects.requireNonNull(prevLineHash32, "prevLineHash32 == null");
|
||||
Objects.requireNonNull(rawBytes, "rawBytes == null");
|
||||
|
||||
if (prevGlobalHash32.length != 32 || prevLineHash32.length != 32)
|
||||
throw new IllegalArgumentException("hash len != 32");
|
||||
|
||||
byte[] loginBytes = userLogin.getBytes(StandardCharsets.UTF_8);
|
||||
if (loginBytes.length > 255)
|
||||
throw new IllegalArgumentException("login >255 bytes");
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(
|
||||
DOMAIN.length +
|
||||
1 + loginBytes.length +
|
||||
32 + 32 +
|
||||
rawBytes.length
|
||||
).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
bb.put(DOMAIN);
|
||||
bb.put((byte) loginBytes.length);
|
||||
bb.put(loginBytes);
|
||||
bb.put(prevGlobalHash32);
|
||||
bb.put(prevLineHash32);
|
||||
bb.put(rawBytes);
|
||||
|
||||
return bb.array();
|
||||
}
|
||||
|
||||
public static byte[] sha256(byte[] data) {
|
||||
try {
|
||||
MessageDigest d = MessageDigest.getInstance("SHA-256");
|
||||
return d.digest(data);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("SHA-256 unavailable", e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: сюда подключается твой Ed25519 util
|
||||
public static boolean verifySignature(byte[] hash32,
|
||||
byte[] signature64,
|
||||
byte[] publicKey32) {
|
||||
// TODO: Ed25519.verify(hash32, signature64, publicKey32)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user