Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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: 0 additions & 3 deletions src/main/java/org/unicitylabs/sdk/api/CertificationData.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ public static CertificationData fromCbor(byte[] bytes) {
* @return certification data
*/
public static CertificationData fromMintTransaction(MintTransaction transaction) {
Objects.requireNonNull(transaction, "transaction cannot be null");

SigningService signingService = MintSigningService.create(transaction.getTokenId());
Comment thread
martti007 marked this conversation as resolved.

return CertificationData.fromTransaction(
Expand All @@ -137,7 +135,6 @@ public static CertificationData fromMintTransaction(MintTransaction transaction)
* @return certification data
*/
public static CertificationData fromTransaction(Transaction transaction, UnlockScript unlockScript) {
Objects.requireNonNull(transaction, "transaction cannot be null");
Objects.requireNonNull(unlockScript, "unlockScript cannot be null");

return CertificationData.fromTransaction(transaction, unlockScript.encode());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.unicitylabs.sdk.transaction.verification;

import org.unicitylabs.sdk.api.bft.RootTrustBase;
import org.unicitylabs.sdk.predicate.verification.PredicateVerifierService;
import org.unicitylabs.sdk.unicityid.CertifiedUnicityIdMintTransaction;
import org.unicitylabs.sdk.util.verification.VerificationResult;
import org.unicitylabs.sdk.util.verification.VerificationStatus;

import java.util.ArrayList;
import java.util.List;

/**
* Verification rule for the genesis (mint) of a unicity id token. Validates the inclusion proof of
* the certified mint transaction.
*/
public class CertifiedUnicityIdMintTransactionVerificationRule {

private CertifiedUnicityIdMintTransactionVerificationRule() {
}

/**
* Verify the certified unicity id mint transaction.
*
* @param trustBase root trust base
* @param predicateVerifier predicate verifier
* @param genesis certified unicity id mint transaction to verify
*
* @return verification result
*/
public static VerificationResult<VerificationStatus> verify(
RootTrustBase trustBase,
PredicateVerifierService predicateVerifier,
CertifiedUnicityIdMintTransaction genesis
) {
List<VerificationResult<?>> results = new ArrayList<>();

VerificationResult<InclusionProofVerificationStatus> result = InclusionProofVerificationRule.verify(
trustBase,
predicateVerifier,
genesis.getInclusionProof(),
genesis
);
results.add(result);
if (result.getStatus() != InclusionProofVerificationStatus.OK) {
return new VerificationResult<>(
"CertifiedUnicityIdMintTransactionVerificationRule",
VerificationStatus.FAIL,
String.format("Inclusion proof verification failed: %s", result.getStatus()),
results
);
}

return new VerificationResult<>(
"CertifiedUnicityIdMintTransactionVerificationRule",
VerificationStatus.OK,
"",
results
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package org.unicitylabs.sdk.unicityid;

import org.unicitylabs.sdk.api.InclusionProof;
import org.unicitylabs.sdk.api.bft.RootTrustBase;
import org.unicitylabs.sdk.crypto.hash.DataHash;
import org.unicitylabs.sdk.predicate.Predicate;
import org.unicitylabs.sdk.predicate.builtin.PayToPublicKeyPredicate;
import org.unicitylabs.sdk.predicate.verification.PredicateVerifierService;
import org.unicitylabs.sdk.serializer.cbor.CborDeserializer;
import org.unicitylabs.sdk.serializer.cbor.CborSerializer;
import org.unicitylabs.sdk.transaction.TokenId;
import org.unicitylabs.sdk.transaction.TokenType;
import org.unicitylabs.sdk.transaction.Transaction;
import org.unicitylabs.sdk.transaction.verification.InclusionProofVerificationRule;
import org.unicitylabs.sdk.transaction.verification.InclusionProofVerificationStatus;
import org.unicitylabs.sdk.util.verification.VerificationException;
import org.unicitylabs.sdk.util.verification.VerificationResult;

import java.util.List;
import java.util.Optional;

/**
* Unicity id mint transaction bundled with a verified inclusion proof.
*/
public final class CertifiedUnicityIdMintTransaction implements Transaction {

private final UnicityIdMintTransaction transaction;
private final InclusionProof inclusionProof;

private CertifiedUnicityIdMintTransaction(UnicityIdMintTransaction transaction,
InclusionProof inclusionProof) {
this.transaction = transaction;
this.inclusionProof = inclusionProof;
}

@Override
public Optional<byte[]> getData() {
return this.transaction.getData();
}

@Override
public Predicate getLockScript() {
return this.transaction.getLockScript();
}

@Override
public Predicate getRecipient() {
return this.transaction.getRecipient();
}

@Override
public DataHash getSourceStateHash() {
return this.transaction.getSourceStateHash();
}

@Override
public byte[] getStateMask() {
return this.transaction.getStateMask();
}

/**
* Returns the token id derived from the unicity id.
*
* @return token id
*/
public TokenId getTokenId() {
return this.transaction.getTokenId();
}

/**
* Returns the token type.
*
* @return token type
*/
public TokenType getTokenType() {
return this.transaction.getTokenType();
}

/**
* Returns the target predicate.
*
* @return target predicate
*/
public PayToPublicKeyPredicate getTargetPredicate() {
return this.transaction.getTargetPredicate();
}

/**
* Returns the unicity id.
*
* @return unicity id
*/
public UnicityId getUnicityId() {
return this.transaction.getUnicityId();
}

/**
* Returns the inclusion proof certifying this transaction.
*
* @return inclusion proof
*/
public InclusionProof getInclusionProof() {
return this.inclusionProof;
}

/**
* Deserializes a certified unicity id mint transaction from CBOR.
*
* @param bytes CBOR-encoded certified mint transaction
*
* @return decoded certified mint transaction
*/
public static CertifiedUnicityIdMintTransaction fromCbor(byte[] bytes) {
List<byte[]> data = CborDeserializer.decodeArray(bytes);
return new CertifiedUnicityIdMintTransaction(
UnicityIdMintTransaction.fromCbor(data.get(0)),
InclusionProof.fromCbor(data.get(1))
);
Comment thread
martti007 marked this conversation as resolved.
Outdated
}

/**
* Creates a certified unicity id mint transaction after verifying its inclusion proof.
*
* @param trustBase trust base used to verify inclusion proof signatures
* @param predicateVerifier predicate verifier service
* @param transaction unicity id mint transaction to certify
* @param inclusionProof inclusion proof for the transaction
*
* @return certified mint transaction
*
* @throws VerificationException if inclusion proof verification fails
*/
public static CertifiedUnicityIdMintTransaction fromTransaction(
RootTrustBase trustBase,
PredicateVerifierService predicateVerifier,
UnicityIdMintTransaction transaction,
InclusionProof inclusionProof
) {
VerificationResult<InclusionProofVerificationStatus> result = InclusionProofVerificationRule.verify(
trustBase,
predicateVerifier,
inclusionProof,
transaction
);
if (result.getStatus() != InclusionProofVerificationStatus.OK) {
throw new VerificationException("Inclusion proof verification failed", result);
}

return new CertifiedUnicityIdMintTransaction(transaction, inclusionProof);
}

@Override
public DataHash calculateStateHash() {
return this.transaction.calculateStateHash();
}

@Override
public DataHash calculateTransactionHash() {
return this.transaction.calculateTransactionHash();
}

@Override
public byte[] toCbor() {
return CborSerializer.encodeArray(this.transaction.toCbor(), this.inclusionProof.toCbor());
}

@Override
public String toString() {
return String.format("CertifiedUnicityIdMintTransaction{transaction=%s, inclusionProof=%s}",
this.transaction, this.inclusionProof);
}
}
127 changes: 127 additions & 0 deletions src/main/java/org/unicitylabs/sdk/unicityid/UnicityId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package org.unicitylabs.sdk.unicityid;

import org.unicitylabs.sdk.crypto.hash.DataHash;
import org.unicitylabs.sdk.crypto.hash.DataHasher;
import org.unicitylabs.sdk.crypto.hash.HashAlgorithm;
import org.unicitylabs.sdk.serializer.cbor.CborDeserializer;
import org.unicitylabs.sdk.serializer.cbor.CborSerializer;
import org.unicitylabs.sdk.transaction.TokenId;

import java.util.List;
import java.util.Objects;

/**
* Human-readable identifier for a unicity token. The pair (domain, name) is hashed deterministically
* to derive the corresponding {@link TokenId}.
*/
public final class UnicityId {

private final String name;
private final String domain;

/**
* Create a unicity id with name only (no domain).
*
* @param name token name
*/
public UnicityId(String name) {
this(name, null);
}

/**
* Create a unicity id.
*
* @param name token name
* @param domain optional domain; may be null
*/
public UnicityId(String name, String domain) {
this.name = Objects.requireNonNull(name, "name cannot be null");
this.domain = domain;
}

/**
* Get the token name.
*
* @return name
*/
public String getName() {
return this.name;
}

/**
* Get the optional domain.
*
* @return domain, or null if not set
*/
public String getDomain() {
return this.domain;
}

/**
* Deserialize a unicity id from CBOR bytes.
*
* @param bytes CBOR bytes
*
* @return unicity id
*/
public static UnicityId fromCbor(byte[] bytes) {
List<byte[]> data = CborDeserializer.decodeArray(bytes);
return new UnicityId(
CborDeserializer.decodeTextString(data.get(0)),
CborDeserializer.decodeNullable(data.get(1), CborDeserializer::decodeTextString)
);
Comment thread
martti007 marked this conversation as resolved.
Outdated
}

/**
* Serialize the unicity id to CBOR bytes.
*
* @return CBOR bytes
*/
public byte[] toCbor() {
return CborSerializer.encodeArray(
CborSerializer.encodeTextString(this.name),
CborSerializer.encodeNullable(this.domain, CborSerializer::encodeTextString)
);
}

/**
* Derive the token id from this unicity id by hashing the tagged ("NAMETAG_", domain, name)
* tuple with SHA-256.
*
* @return derived token id
*/
public TokenId toTokenId() {
DataHash hash = new DataHasher(HashAlgorithm.SHA256)
.update(
CborSerializer.encodeArray(
CborSerializer.encodeTextString("NAMETAG_"),
CborSerializer.encodeNullable(this.domain, CborSerializer::encodeTextString),
CborSerializer.encodeTextString(this.name)
)
)
.digest();
return new TokenId(hash.getData());
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof UnicityId)) {
return false;
}
UnicityId that = (UnicityId) o;
return this.name.equals(that.name) && Objects.equals(this.domain, that.domain);
}

@Override
public int hashCode() {
return Objects.hash(this.name, this.domain);
}

@Override
public String toString() {
return "@" + (this.domain != null ? this.domain + "/" : "") + this.name;
}
}
Loading
Loading