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

Implement cip 67 #350

Merged
merged 5 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions cip/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dependencies {
api project(':cip:cip25')
api project(':cip:cip27')
api project(':cip:cip30')
api project(':cip:cip67')
}

publishing {
Expand Down
5 changes: 5 additions & 0 deletions cip/cip67/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# CIP-67 (cardano-client-cip67)

[CIP 67 - Asset Name Label Registry](https://cips.cardano.org/cip/CIP-0067)

**Dependencies:** crypto
15 changes: 15 additions & 0 deletions cip/cip67/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
dependencies {
api project(':crypto')
api project(':common')
}

publishing {
publications {
mavenJava(MavenPublication) {
pom {
name = 'Cardano Client CIP67'
description = 'Cardano Client Lib - CIP67 Implementation'
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.bloxbean.cardano.client.cip.cip67;

import com.bloxbean.cardano.client.crypto.CRC8;
import com.bloxbean.cardano.client.util.IntUtil;

import java.nio.ByteBuffer;

public class CIP67 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Kammerlo

Should we rename CIP67 to CIP67AssetName or CIP67AssetNameUtil to give some context ?


private CIP67() {
throw new IllegalStateException("Utility class");
}

/**
* Converts a label to the CIP67 asset name
* @param label decimal range: [0, 65535]
* @return prefix as bytes representation
*/
public static byte[] labelToPrefix(int label) {
int crc = CRC8.applyCRC8(IntUtil.intToByteArray(label));

int value = 1;
value = label << 12;
value += crc << 4;
return IntUtil.intToByteArray(value);
}

/**
* Gets the asset name label from CIP67 asset name. In this method no verification is done.
* @param labelBytes prefix as byte representation
* @return decimal range: [0, 65535]
*/
public static int prefixToLabel(byte[] labelBytes) {
int assetName = ByteBuffer.wrap(labelBytes).getInt();
int labelNum = assetName >> 12;
labelNum = labelNum & 0x3FFFFFF; // to avoid wrong padding
return labelNum;
}

/**
* Verifies if the asset name is valid with CIP67.
* @param assetName prefix to check
* @return true if valid padding and checksum check passed
*/
public static boolean isValidAssetName(int assetName) {
return isValidPadding(assetName) && verifyCheckSum(assetName);
}

/**
* Verification if the asset name contains leading and following 0000
* @param assetName prefix to check
* @return true if padding is valid
*/
private static boolean isValidPadding(int assetName) {
return (assetName & 0xC000003) == 0;
}

/**
* Verification if the label and CRC-8 checksum are valid within the asset name
* @param assetName prefix to check
* @return true if checksum is verified
*/
private static boolean verifyCheckSum(int assetName) {
byte[] labelAsBytes = IntUtil.intToByteArray(assetName);
int label = prefixToLabel(labelAsBytes);
int checkSum = getCheckSum(labelAsBytes);
return checkSum == CRC8.applyCRC8(IntUtil.intToByteArray(label));
}

/**
* Extracts the checksum out of the asset name
* @param labelBytes asset label as bytes
* @return calculated checksum according to CRC-8
*/
private static int getCheckSum(byte[] labelBytes) {
int assetName = ByteBuffer.wrap(labelBytes).getInt();
assetName = assetName >> 4;
byte[] intToByteArray = IntUtil.intToByteArray(assetName);
return intToByteArray[3]; // get the last Byte from label without the zero padding
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implementation of CIP67 to get labels and verify it from the asset name.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.bloxbean.cardano.client.cip.cip67;

import org.junit.jupiter.api.Test;

import java.util.Arrays;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class CIP67Test {

@Test
void labelToPrefixTest() {
byte[] prefixAsBytes = CIP67.labelToPrefix(222);
byte[] expectedValue = {0, 13, -31, 64};
assertTrue(Arrays.equals(prefixAsBytes, expectedValue)); // corresponding to 0x000de140
}

@Test
void prefixToLabelTest() {
int label = 0;
label = CIP67.prefixToLabel(new byte[]{0, 13, -31, 64});
assertEquals(222, label);
}

@Test
void isValidAssetNameTestCorrectName() {
boolean isValid = CIP67.isValidAssetName(0x000de140);
assertEquals(true, isValid);
}

@Test
void isValidAssetNameTestWrongPadding() {
boolean isValid = CIP67.isValidAssetName(0x000de141);
assertEquals(false, isValid);

isValid = CIP67.isValidAssetName(0x100de140);
assertEquals(false, isValid);
}

@Test
void isValidAssetNameWrongChecksum() {
boolean isValid = CIP67.isValidAssetName(0x000de130);
assertEquals(false, isValid);
}
}
20 changes: 20 additions & 0 deletions common/src/main/java/com/bloxbean/cardano/client/util/IntUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.bloxbean.cardano.client.util;

public class IntUtil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a Utils class which has a method with similar functionality uint32ToByteArrayBE. But it's currently in crypto/bip32 package.

I am just wondering if we can use that. Otherwise, we can keep this class but rename it to ByteUtil, allowing us to add additional conversion methods, such as long to bytes, etc later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So yes the function would work as well. For me this conversions seemed pretty common so I wasn't looking into the bip32 package for this functionality.
I renamed the package. We can discuss if moving the other functions to a more common place.


public static byte[] intToByteArray(int value) {
return new byte[] {
(byte)(value >>> 24),
(byte)(value >>> 16),
(byte)(value >>> 8),
(byte)value};
}

public static int byteArrayToInt(byte[] input) {
int value = 0;
for(byte b : input) {
value = (value << 8) + (b & 0xFF);
}
return value;
}
}
30 changes: 30 additions & 0 deletions crypto/src/main/java/com/bloxbean/cardano/client/crypto/CRC8.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.bloxbean.cardano.client.crypto;

import com.bloxbean.cardano.client.util.IntUtil;

public class CRC8 {

public static int[] LOOKUP = new int[] {
0x00,0x07,0x0e,0x09,0x1c,0x1b,0x12,0x15,0x38,0x3f,0x36,0x31,0x24,0x23,0x2a,0x2d,0x70,0x77,0x7e,0x79,0x6c,0x6b,0x62,0x65,0x48,0x4f,0x46,0x41,0x54,0x53,0x5a,0x5d,
0xe0,0xe7,0xee,0xe9,0xfc,0xfb,0xf2,0xf5,0xd8,0xdf,0xd6,0xd1,0xc4,0xc3,0xca,0xcd,0x90,0x97,0x9e,0x99,0x8c,0x8b,0x82,0x85,0xa8,0xaf,0xa6,0xa1,0xb4,0xb3,0xba,0xbd,
0xc7,0xc0,0xc9,0xce,0xdb,0xdc,0xd5,0xd2,0xff,0xf8,0xf1,0xf6,0xe3,0xe4,0xed,0xea,0xb7,0xb0,0xb9,0xbe,0xab,0xac,0xa5,0xa2,0x8f,0x88,0x81,0x86,0x93,0x94,0x9d,0x9a,
0x27,0x20,0x29,0x2e,0x3b,0x3c,0x35,0x32,0x1f,0x18,0x11,0x16,0x03,0x04,0x0d,0x0a,0x57,0x50,0x59,0x5e,0x4b,0x4c,0x45,0x42,0x6f,0x68,0x61,0x66,0x73,0x74,0x7d,0x7a,
0x89,0x8e,0x87,0x80,0x95,0x92,0x9b,0x9c,0xb1,0xb6,0xbf,0xb8,0xad,0xaa,0xa3,0xa4,0xf9,0xfe,0xf7,0xf0,0xe5,0xe2,0xeb,0xec,0xc1,0xc6,0xcf,0xc8,0xdd,0xda,0xd3,0xd4,
0x69,0x6e,0x67,0x60,0x75,0x72,0x7b,0x7c,0x51,0x56,0x5f,0x58,0x4d,0x4a,0x43,0x44,0x19,0x1e,0x17,0x10,0x05,0x02,0x0b,0x0c,0x21,0x26,0x2f,0x28,0x3d,0x3a,0x33,0x34,
0x4e,0x49,0x40,0x47,0x52,0x55,0x5c,0x5b,0x76,0x71,0x78,0x7f,0x6a,0x6d,0x64,0x63,0x3e,0x39,0x30,0x37,0x22,0x25,0x2c,0x2b,0x06,0x01,0x08,0x0f,0x1a,0x1d,0x14,0x13,
0xae,0xa9,0xa0,0xa7,0xb2,0xb5,0xbc,0xbb,0x96,0x91,0x98,0x9f,0x8a,0x8d,0x84,0x83,0xde,0xd9,0xd0,0xd7,0xc2,0xc5,0xcc,0xcb,0xe6,0xe1,0xe8,0xef,0xfa,0xfd,0xf4,0xf3,
};

public static int applyCRC8(byte[] input) {
int crc = 0;
for (int i = 0; i < input.length; i ++) {
crc = LOOKUP[(crc ^ input[i]) & 0xFF] & 0xFF;
}
return crc;
}

public static int applyCRC8(int input) {
byte[] inputAsBytes = IntUtil.intToByteArray(input);
return applyCRC8(inputAsBytes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.bloxbean.cardano.client.crypto;

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

import org.junit.jupiter.api.Test;

public class CRC8Test {

@Test
public void testCRC8Encoding() {
int crc8CheckSum = CRC8.applyCRC8(222);
assertEquals(crc8CheckSum, 0x14);
}

}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ include 'cip:cip25'
include 'cip:cip8'
include 'cip:cip27'
include 'cip:cip30'
include 'cip:cip67'

//Backend modules
include 'backend'
Expand Down
Loading