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

Version bump #302

Merged
merged 5 commits into from
Jun 28, 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
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ apply plugin: 'java'

group = 'network.casper'
// Version number update for release
version='2.5.8'
version='2.5.9'
sourceCompatibility = 1.8
targetCompatibility = 1.8

Expand Down Expand Up @@ -49,6 +49,7 @@ dependencies {
testImplementation "org.junit.jupiter:junit-jupiter:${jupiterVersion}"
// Used to compare json strings while testing
testImplementation "org.skyscreamer:jsonassert:${jsonassertVersion}"
testImplementation files('assets')
}

java {
Expand Down
4 changes: 4 additions & 0 deletions script/debug-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
cd "$(dirname "$0")/.."|| exit 1
./gradlew --stop
./gradlew cleanTest test -Dorg.gradle.jvmargs='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005' --no-daemon --debug-jvm
2 changes: 1 addition & 1 deletion script/docker-run
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
# run the cspr-nctl container in docker
docker run --rm -it --name cspr-nctl -d -p 25101:25101 -p 11101:11101 -p 14101:14101 -p 18101:18101 stormeye2000/cspr-nctl:linux-1.5.5
docker run --rm -it --name cspr-nctl -d -p 25101:25101 -p 11101:11101 -p 14101:14101 -p 18101:18101 stormeye2000/cspr-nctl:release-1.5.5
34 changes: 13 additions & 21 deletions src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.syntifi.crypto.key;

import com.casper.sdk.model.key.AlgorithmTag;
import com.syntifi.crypto.key.encdec.Hex;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.bouncycastle.asn1.*;
Expand Down Expand Up @@ -98,7 +97,7 @@ public Boolean verify(byte[] message, byte[] signature) {

if (recoveredKey != null) {

final byte[] keyFromSignature = getRecoveredShortKey(recoveredKey.toByteArray());
final byte[] keyFromSignature = getShortKey(recoveredKey.toByteArray());

if (Arrays.equals(keyFromSignature, keyToFind)) {
return true;
Expand All @@ -114,32 +113,25 @@ public Boolean verify(byte[] message, byte[] signature) {

/**
* Gets a short key
*
* @param key the key as a byte array
* @return short key as byte array
*/
public static byte[] getShortKey(final byte[] key) {
final BigInteger pubKey = new BigInteger(key);
final String pubKeyPrefix = pubKey.testBit(0) ? "03" : "02";
final byte[] pubKeyBytes = Arrays.copyOfRange(key, 0, (AlgorithmTag.SECP256K1.getLength() - 1));
return Hex.decode(pubKeyPrefix + Hex.encode(pubKeyBytes));
}

/**
* There's around a 50% chance the elliptical curve algo will generate a 65 byte
* public key instead of 66 byte.
* Luckily the algo pads the first byte as zero when this happens
* Determine this and then return the byte array to be shortened
* startBit determines this
*
* @param key the key as a byte array
* @return short key as byte array
*/
public static byte[] getRecoveredShortKey(final byte[] key){
if (key[0] == (byte) 0) {
return getShortKey(Arrays.copyOfRange(key, 1, (key.length - 1)));
} else {
return getShortKey(key);
}
public static byte[] getShortKey(final byte[] key) {

final int startBit = key[0] == (byte) 0 ? 1 : 0;

final byte[] shortKey = new byte[AlgorithmTag.SECP256K1.getLength()];
shortKey[0] = (byte) (new BigInteger(key).testBit(0) ? 3 : 2);

System.arraycopy(key, startBit, shortKey, 1, AlgorithmTag.SECP256K1.getLength() - 1);

return shortKey;

}

}
96 changes: 93 additions & 3 deletions src/test/java/com/casper/sdk/service/CasperServiceTestsNctl.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.casper.sdk.service;

import com.casper.sdk.exception.CasperInvalidStateException;
import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.helper.CasperTransferHelper;
import com.casper.sdk.identifier.block.HashBlockIdentifier;
import com.casper.sdk.identifier.block.HeightBlockIdentifier;
import com.casper.sdk.identifier.global.GlobalStateIdentifier;
Expand All @@ -9,22 +11,29 @@
import com.casper.sdk.identifier.purse.PurseIdentifier;
import com.casper.sdk.model.balance.QueryBalanceData;
import com.casper.sdk.model.block.JsonBlockData;
import com.casper.sdk.model.common.Ttl;
import com.casper.sdk.model.deploy.Deploy;
import com.casper.sdk.model.deploy.DeployData;
import com.casper.sdk.model.deploy.DeployResult;
import com.casper.sdk.model.era.EraInfoData;
import com.casper.sdk.model.key.PublicKey;
import com.casper.sdk.model.status.ChainspecData;
import com.casper.sdk.model.status.StatusData;
import com.syntifi.crypto.key.AbstractPrivateKey;
import com.syntifi.crypto.key.Ed25519PrivateKey;
import org.junit.Ignore;
import com.syntifi.crypto.key.*;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

Expand Down Expand Up @@ -179,5 +188,86 @@ void getGlobalStateAndReadAsString() {
}
}

/**
* We're testing the 50% Secp problem here
* When a Secp public key is generated from prime numbers, there's a 50% chance it will 65bit or 66bit
* When it's 65% the long public key is padded with zero
* This test uses a Secp private key that will generate a 65bit padded public key
*/
@Test
void testDeployWithPaddedPublicKey() throws URISyntaxException, IOException, NoSuchTypeException, GeneralSecurityException, ValueSerializationException {

DeployData deploy;

//First fund the private-padded.pem account from the faucet account
final Ed25519PrivateKey faucetPrivateKey = new Ed25519PrivateKey();
final URL faucetKey = getClass().getResource("/net-1/faucet/secret_key.pem");
assert faucetKey != null;
faucetPrivateKey.readPrivateKey(faucetKey.getFile());

Secp256k1PrivateKey paddedPrivateKey = new Secp256k1PrivateKey();
String filePath = getResourcesKeyPath("secp256k1/private-padded.pem");
paddedPrivateKey.readPrivateKey(filePath);


byte[] paddedPublicKeyFull = paddedPrivateKey.getKeyPair().getPublicKey().toByteArray();
assert paddedPublicKeyFull[0] == (byte) 0;

DeployResult deployResult = doDeploy(faucetPrivateKey, paddedPrivateKey.derivePublicKey());

assert deployResult != null;

//wait for deploy to be accepted
do {
deploy = casperServiceNctl.getDeploy(deployResult.getDeployHash());
} while (deploy.getDeploy().getApprovals() == null || deploy.getDeploy().getApprovals().size() <= 0);


//Now transfer from private-padded.pem to another user
Secp256k1PrivateKey toPrivateKey = new Secp256k1PrivateKey();
filePath = getResourcesKeyPath("secp256k1/secret_key.pem");
toPrivateKey.readPrivateKey(filePath);

deployResult = doDeploy(paddedPrivateKey, toPrivateKey.derivePublicKey());

assert deployResult != null;

//wait for deploy to be accepted
do {
deploy = casperServiceNctl.getDeploy(deployResult.getDeployHash());
} while (deploy.getDeploy().getApprovals() == null || deploy.getDeploy().getApprovals().size() <= 0);


assert Arrays.equals(deploy.getDeploy().getApprovals().get(0).getSigner().getPubKey().getKey(), paddedPrivateKey.derivePublicKey().getKey());

//now verify signature

Secp256k1PublicKey paddedPublicKey = (Secp256k1PublicKey) paddedPrivateKey.derivePublicKey();

assert paddedPublicKey.verify(deploy.getDeploy().getHash().getDigest(), deploy.getDeploy().getApprovals().get(0).getSignature().getKey());

}

private DeployResult doDeploy(final AbstractPrivateKey sk, final AbstractPublicKey pk) throws NoSuchTypeException, GeneralSecurityException, ValueSerializationException {

final Deploy deploy = CasperTransferHelper.buildTransferDeploy(
sk,
PublicKey.fromAbstractPublicKey(pk),
BigInteger.valueOf(2500000000L),
"casper-net-1",
Math.abs(new Random().nextLong()),
BigInteger.valueOf(100000000L),
1L,
Ttl.builder().ttl("30m").build(),
new Date(),
new ArrayList<>());

return casperServiceNctl.putDeploy(deploy);
}


protected String getResourcesKeyPath(String filename) throws URISyntaxException {
return Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource(filename)).toURI()).toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
Expand Down Expand Up @@ -82,7 +81,7 @@ void sign_should_sign_message() throws URISyntaxException, IOException {
}

@Test
void create_random_key() throws GeneralSecurityException, IOException {
void create_random_key() {
Secp256k1PrivateKey sk = Secp256k1PrivateKey.deriveRandomKey();
Secp256k1PublicKey pk = (Secp256k1PublicKey) sk.derivePublicKey();
LOGGER.info(sk.getKeyPair().getPrivateKey().toString(16));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,31 @@ void verify_should_be_ok() throws URISyntaxException, IOException {
}

@Test
void signAndRecoverPublicKey_1() throws URISyntaxException, IOException {
void signAndRecoverPublicKeyWithPaddedPK() throws URISyntaxException, IOException {

//Get the private key
Secp256k1PrivateKey privKey = new Secp256k1PrivateKey();
String filePath = getResourcesKeyPath("secp256k1/private-padded.pem");
privKey.readPrivateKey(filePath);

//Check that the public key is private-padded.pem with a 0 byte
assert privKey.getKeyPair().getPublicKey().toByteArray()[0] == (byte) 0;


//Derive the public key
Secp256k1PublicKey publicKey = (Secp256k1PublicKey) privKey.derivePublicKey();

String message = "bc81ca4de9b3a991a6514eddf0e994e0035c7ba58f333c4d7ba5dd18b4c9c547";

//Generate the signature
byte[] signature = privKey.sign(message.getBytes());

//Test
assert publicKey.verify(message.getBytes(), signature);

}
@Test
void signAndRecoverPublicKey_1() throws URISyntaxException, IOException {

//Get the private key
Secp256k1PrivateKey privKey = new Secp256k1PrivateKey();
Expand Down
3 changes: 3 additions & 0 deletions src/test/resources/secp256k1/private-padded.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN EC PRIVATE KEY-----
MC4CAQEEIF6d87JG1raI7KNzkaXUbtTezTHE7oziYJ04VGZv4YOdoAcGBSuBBAAK
-----END EC PRIVATE KEY-----
Loading