CIP8 API
CIP8 (Cardano Improvement Proposal 8) defines a standard for message signing using COSE (CBOR Object Signing and Encryption) signatures. The Cardano Client Library exposes builders and models for COSE Sign1 and COSE Sign so you can create and verify signatures that follow the specification. The focus is on providing small, composable pieces: you assemble headers, build a SigStructure, sign with your own signing provider, and serialize/deserialise with the COSE models.
Key Features
- COSE Sign1 and Sign builders
- Payload hashing toggle (Blake2b-224)
- Header helpers for protected and unprotected maps
- COSE key utilities for crv/x headers and serialization
Dependencies
- Group ID: com.bloxbean.cardano
- Artifact ID: cardano-client-cip8
- Dependencies: common, crypto
Usage Examples
Creating COSE Sign1 Signatures
// Protected headers (algorithm + optional content type or key id)
HeaderMap protectedHeaders = new HeaderMap()
.algorithmId(14) // EdDSA
.contentType(-1000); // Optional content type
// Unprotected headers for custom values
HeaderMap unprotectedHeaders = new HeaderMap()
.addOtherHeader(-100, "Some header value");
Headers headers = new Headers()
._protected(new ProtectedHeaderMap(protectedHeaders))
.unprotected(unprotectedHeaders);
byte[] payload = "Hello World".getBytes(StandardCharsets.UTF_8);
COSESign1Builder builder = new COSESign1Builder(headers, payload, false)
.hashed(true); // Blake2b-224 hashing of payload
SigStructure sigStructure = builder.makeDataToSign();
byte[] signature = signingProvider.sign(sigStructure.serializeAsBytes(), privateKeyBytes);
COSESign1 coseSign1 = builder.build(signature);
byte[] serialized = coseSign1.serializeAsBytes();
String hexSignature = HexUtil.encodeHexString(serialized);Creating COSE Sign Signatures (Multiple Signers)
Headers headers = new Headers()
._protected(new ProtectedHeaderMap(new HeaderMap().algorithmId(14)))
.unprotected(new HeaderMap());
byte[] payload = "Multi-signer message".getBytes(StandardCharsets.UTF_8);
COSESignBuilder builder = new COSESignBuilder(headers, payload, false)
.hashed(true);
SigStructure sigStructure = builder.makeDataToSign();
List<COSESignature> signatures = new ArrayList<>();
for (byte[] pvtKey : signerPrivateKeys) {
byte[] sig = signingProvider.sign(sigStructure.serializeAsBytes(), pvtKey);
signatures.add(new COSESignature().signature(sig));
}
COSESign coseSign = builder.build(signatures);
byte[] serialized = coseSign.serializeAsBytes();Signature Verification
COSESign1 exposes signedData() to reconstruct the SigStructure for verification.
COSESign1 coseSign1 = COSESign1.deserialize(signatureBytes);
SigStructure signedData = coseSign1.signedData();
boolean isValid = signingProvider.verify(
coseSign1.signature(),
signedData.serializeAsBytes(),
publicKeyBytes);
byte[] payload = coseSign1.payload();Working with Headers
Headers headers = coseSign1.headers();
HeaderMap protectedHeaders = headers._protected().getAsHeaderMap();
HeaderMap unprotectedHeaders = headers.unprotected();
Object algorithmId = protectedHeaders.algorithmId();
Object contentType = protectedHeaders.contentType();
byte[] keyId = protectedHeaders.keyId();
byte[] customValue = unprotectedHeaders.otherHeaderAsBytes(-100);Creating COSE Keys
COSEKey stores standard fields plus arbitrary other headers (e.g., crv, x).
COSEKey coseKey = new COSEKey()
.keyType(1) // Octet Key Pair
.algorithmId(14) // EdDSA
.addOtherHeader(-1, new UnsignedInteger(6)) // crv (Ed25519)
.addOtherHeader(-2, new ByteString(publicKeyBytes));
byte[] keyBytes = coseKey.serializeAsBytes();
COSEKey deserializedKey = COSEKey.deserialize(keyBytes);
byte[] extractedPublicKey = deserializedKey.otherHeaderAsBytes(-2);API Reference
Core Classes
COSESign1Builder
Builder class for creating COSE Sign1 signatures.
// Constructor
COSESign1Builder(Headers headers, byte[] payload, boolean isPayloadExternal)
// Methods
SigStructure makeDataToSign() // Create signature structure
COSESign1 build(byte[] signature) // Build final signature
COSESign1Builder hashed(boolean hashed) // Enable Blake2b-224 hashingCOSESignBuilder
Builder class for creating COSE Sign signatures with multiple signers.
// Constructor
COSESignBuilder(Headers headers, byte[] payload, boolean isPayloadExternal)
// Methods
SigStructure makeDataToSign() // Create signature structure
COSESign build(List<COSESignature> signatures) // Build final signature
COSESignBuilder hashed(boolean hashed) // Enable Blake2b-224 hashingHeaders
Manages protected and unprotected headers.
Headers() // use fluent setters
// Methods
Headers _protected(ProtectedHeaderMap protectedHeaders)
Headers unprotected(HeaderMap unprotectedHeaders)
HeaderMap _protected().getAsHeaderMap() // Decode protected map
HeaderMap unprotected() // Get unprotected headers
Headers copy() // Create a copyHeaderMap
Manages individual header maps.
// Methods
HeaderMap algorithmId(long or String algorithmId)
HeaderMap contentType(long or String contentType)
HeaderMap keyId(byte[] keyId)
HeaderMap addOtherHeader(long key, Object value) // Custom header
Object algorithmId()
Object contentType()
byte[] keyId()
byte[] otherHeaderAsBytes(long key)
long otherHeaderAsLong(long key)
String otherHeaderAsString(long key)COSEKey
Represents a COSE key map.
COSEKey keyType(long or String)
COSEKey algorithmId(long or String)
COSEKey addOtherHeader(long key, DataItem value)
COSEKey addOtherHeader(long key, long/String/BigInteger/byte[] value)
byte[] serializeAsBytes()
COSEKey deserialize(byte[] bytes)
byte[] otherHeaderAsBytes(long key)
long otherHeaderAsLong(long key)
String otherHeaderAsString(long key)CIP8 Specification Details
COSE Sign1 Structure
Components describe exactly what is signed and carried in the CBOR array:
- Protected Headers: Algorithm ID, content type, key ID
- Unprotected Headers: Custom headers
- Payload: Message data (optionally hashed with Blake2b-224)
- Signature: EdDSA signature over the structure
Signature Process
- Header Creation: Set protected/unprotected headers with algorithm, optional content type, and custom keys.
- Payload Preparation: Optionally hash payload with Blake2b-224 (
hashed(true)). - Structure Building:
makeDataToSign()yields the Sig_Structure the signer must sign. - Signing: Sign the serialized Sig_Structure using EdDSA with your signing provider.
- Serialization: Build
COSESign1and encode viaserializeAsBytes().
Algorithm Identifiers
- 14: EdDSA (Edwards Curve Digital Signature Algorithm)
- 1: Octet Key Pair key type
Advanced CIP8 Features
COSE Encryption
Encryption helpers are available as low-level containers:
COSEEncryptholds headers, ciphertext, and recipients.PasswordEncryptionwraps aCOSEEncrypt0instance (tag 16).PubKeyEncryptionwraps aCOSEEncryptinstance (tag 96).
You construct the underlying COSEEncrypt/COSEEncrypt0 yourself and then wrap it if you need the tagged form.
Integration with Other CIPs
- CIP30: Uses CIP8 for dApp wallet data signing
- CIP25: Can include CIP8 signatures in NFT metadata
- CIP68: Can include CIP8 signatures in datum metadata
For more information about CIP8, refer to the official CIP8 specification .