Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issues/219 - Fix for PublicKey byte deserialization. #255

Merged
merged 2 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import dev.oak3.sbs4j.DeserializerBuffer;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import dev.oak3.sbs4j.util.ByteUtils;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand Down Expand Up @@ -54,7 +53,7 @@ protected void serializeValue(final SerializerBuffer ser) throws ValueSerializat

@Override
public void deserializeCustom(final DeserializerBuffer deser) throws Exception {
this.setValue(PublicKey.fromTaggedHexString(ByteUtils.encodeHexString(deser.readByteArray(33))));
this.setValue(PublicKey.deserialize(deser));
}

@Override
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/com/casper/sdk/model/key/AlgorithmTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum AlgorithmTag implements Tag {
SECP256K1((byte) 0x02), ED25519((byte) 0x01);
SECP256K1((byte) 0x02, 33), ED25519((byte) 0x01, 32);

private final byte byteTag;
/** The number of bytes for a key excluding the tag byte */
private final int length;

public static AlgorithmTag getByTag(byte byteTag) throws NoSuchAlgorithmException {
for (AlgorithmTag a : values()) {
Expand All @@ -29,4 +31,5 @@ public static AlgorithmTag getByTag(byte byteTag) throws NoSuchAlgorithmExceptio
}
throw new NoSuchAlgorithmException();
}

}
40 changes: 25 additions & 15 deletions src/main/java/com/casper/sdk/model/key/PublicKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
import com.syntifi.crypto.key.Ed25519PublicKey;
import com.syntifi.crypto.key.Secp256k1PublicKey;
import com.syntifi.crypto.key.hash.Blake2b;
import dev.oak3.sbs4j.DeserializerBuffer;
import dev.oak3.sbs4j.exception.ValueDeserializationException;
import dev.oak3.sbs4j.util.ByteUtils;
import lombok.NoArgsConstructor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

Expand All @@ -29,39 +32,46 @@ public class PublicKey extends AbstractSerializedKeyTaggedHex<AlgorithmTag> {

public static PublicKey fromTaggedHexString(String hex)
throws NoSuchAlgorithmException, IllegalArgumentException {
byte[] bytes = ByteUtils.parseHexString(hex);
return PublicKey.fromBytes(bytes);
return PublicKey.fromBytes(ByteUtils.parseHexString(hex));
}

public static PublicKey fromBytes(byte[] bytes) throws NoSuchAlgorithmException {
PublicKey object = new PublicKey();
public static PublicKey fromBytes(final byte[] bytes) throws NoSuchAlgorithmException {
final PublicKey object = new PublicKey();
object.setTag(AlgorithmTag.getByTag(bytes[0]));
object.setKey(Arrays.copyOfRange(bytes, 1, bytes.length));

return object;
}

public static PublicKey fromAbstractPublicKey(AbstractPublicKey key) {
PublicKey object = new PublicKey();
object.setTag((key instanceof Secp256k1PublicKey)
? AlgorithmTag.SECP256K1
: AlgorithmTag.ED25519);
public static PublicKey fromAbstractPublicKey(final AbstractPublicKey key) {
final PublicKey object = new PublicKey();
object.setTag((key instanceof Secp256k1PublicKey) ? AlgorithmTag.SECP256K1 : AlgorithmTag.ED25519);
object.setKey(key.getKey());
return object;
}

public String generateAccountHash(boolean includePrefix) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write(getTag().toString().toLowerCase().getBytes("UTF-8"));
public static PublicKey deserialize(final DeserializerBuffer deser) throws ValueDeserializationException, NoSuchAlgorithmException {
// Obtain algorithm tag
final AlgorithmTag tag = AlgorithmTag.getByTag(deser.readU8());
final PublicKey publicKey = new PublicKey();
publicKey.setTag(tag);
// Read the required number of bytes for the algorithm length
publicKey.setKey(deser.readByteArray(tag.getLength()));
return publicKey;
}


public String generateAccountHash(final boolean includePrefix) throws IOException {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write(getTag().toString().toLowerCase().getBytes(StandardCharsets.UTF_8));
byteArrayOutputStream.write(0);
byteArrayOutputStream.write(getKey());

return (includePrefix ? "account-hash-" : "") + ByteUtils.encodeHexString(Blake2b.digest(byteArrayOutputStream.toByteArray(), 32));
}

@JsonCreator
public void createPublicKey(String key) throws NoSuchAlgorithmException, IllegalArgumentException {
PublicKey obj = PublicKey.fromTaggedHexString(key);
public void createPublicKey(final String key) throws NoSuchAlgorithmException, IllegalArgumentException {
final PublicKey obj = PublicKey.fromTaggedHexString(key);
this.setTag(obj.getTag());
this.setKey(obj.getKey());
}
Expand Down
41 changes: 41 additions & 0 deletions src/test/java/com/casper/sdk/model/clvalue/CLValueTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import com.casper.sdk.exception.DynamicInstanceException;
import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.helper.CasperKeyHelper;
import com.casper.sdk.model.clvalue.cltype.*;
import com.casper.sdk.model.clvalue.serde.Target;
import com.casper.sdk.model.deploy.NamedArg;
import com.casper.sdk.model.key.PublicKey;
import com.syntifi.crypto.key.AbstractPublicKey;
import com.syntifi.crypto.key.Ed25519PrivateKey;
import com.syntifi.crypto.key.Secp256k1PrivateKey;
import com.syntifi.crypto.key.encdec.Hex;
import dev.oak3.sbs4j.DeserializerBuffer;
import dev.oak3.sbs4j.SerializerBuffer;
Expand Down Expand Up @@ -323,4 +328,40 @@ void nestedListSerialization() throws Exception {

assertThat(clValueList.getBytes(), is(outerList.getBytes()));
}

@Test
void secp256k1PublicKeySerialization() throws Exception {

final Secp256k1PrivateKey secp256k1PrivateKey = CasperKeyHelper.createRandomSecp256k1Key();
final AbstractPublicKey abstractPublicKey = secp256k1PrivateKey.derivePublicKey();
final PublicKey publicKey = PublicKey.fromAbstractPublicKey(abstractPublicKey);

final CLValuePublicKey clValuePublicKey = new CLValuePublicKey(publicKey);
final SerializerBuffer ser = new SerializerBuffer();
clValuePublicKey.serialize(ser, Target.BYTE);

final byte[] bytes = ser.toByteArray();
assertThat(bytes.length, is(39));

final CLValuePublicKey deserialized = (CLValuePublicKey) clValuePublicKey.deserialize(new DeserializerBuffer(bytes), Target.BYTE);
assertThat(deserialized.getBytes(), is(clValuePublicKey.getBytes()));
}

@Test
void Ed25519PublicKeySerialization() throws Exception {
Ed25519PrivateKey randomEd25519Key = CasperKeyHelper.createRandomEd25519Key();
final AbstractPublicKey abstractPublicKey = randomEd25519Key.derivePublicKey();
final PublicKey publicKey = PublicKey.fromAbstractPublicKey(abstractPublicKey);

final CLValuePublicKey clValuePublicKey = new CLValuePublicKey(publicKey);
final SerializerBuffer ser = new SerializerBuffer();
clValuePublicKey.serialize(ser, Target.BYTE);

final byte[] bytes = ser.toByteArray();
assertThat(bytes.length, is(38));

final CLValuePublicKey deserialized = (CLValuePublicKey) clValuePublicKey.deserialize(new DeserializerBuffer(bytes), Target.BYTE);
assertThat(deserialized.getBytes(), is(clValuePublicKey.getBytes()));
}

}
Loading