-
-
Notifications
You must be signed in to change notification settings - Fork 51
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
Implement cip 67 #350
Changes from 2 commits
b1d7fd7
0a25f19
3e1231e
a28dd88
f870178
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 |
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 { | ||
|
||
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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.bloxbean.cardano.client.util; | ||
|
||
public class IntUtil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a Utils class which has a method with similar functionality 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
||
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; | ||
} | ||
} |
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); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
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 ?