TRISA API
The TRISA Network Protocol implementation exposes several RPCs needed to build TRISA into your organization’s application, which are defined within the protocol buffers. All TRISA members must implement both services described by the TRISA protocol (the TRISANetwork
service and the TRISAHealth
service) to ensure that exchanges are conducted correctly and securely.
The protocol buffers can be compiled into the language of your choice. This section describes the protocol buffers for the TRISANetwork
endpoint and the protocol buffer API in Go.
You will need to download and install the protocol buffer compiler if you have not already.
The TRISANetwork Service
The TRISANetwork
service defines the peer-to-peer interactions between Virtual Asset Providers (VASPs) necessary to conduct compliance information exchanges.
The TRISANetwork Service
has two primary RPCs, Transfer
and TransferStream
. Transfer
and TransferStream
allow VASPs to exchange compliance information before conducting a virtual asset transaction. KeyExchange
allows public keys to exchange so that transaction envelopes can be encrypted and signed.
service TRISANetwork {
rpc Transfer(SecureEnvelope) returns (SecureEnvelope) {}
rpc TransferStream(stream SecureEnvelope) returns (stream SecureEnvelope) {}
rpc ConfirmAddress(Address) returns (AddressConfirmation) {}
rpc KeyExchange(SigningKey) returns (SigningKey) {}
}
The ConfirmAddress
RPC is not currently implemented.
Transfer and TransferStream RPCs
The Transfer
and TransferStream
RPCs conduct the information exchange before a virtual asset transaction. The RPCs enable an originating VASP to send an encrypted transaction envelope to the beneficiary VASP containing a unique ID for the transaction, the encrypted transaction bundle, and metadata associated with the transaction cipher. In response, the beneficiary can validate the transaction request, then return the beneficiary’s transaction information using the same unique transaction ID.
The Transfer
RPC is a unary RPC for simple, single transactions. The TransferStream
RPC is a bidirectional streaming RPC for high throughput transaction workloads.
SecureEnvelope
A SecureEnvelope
is the encrypted transaction envelope that is the outer layer of the TRISA information exchange protocol and facilitates the secure storage of Know Your Client (KYC) data in a transaction. The envelope specifies a unique id to reference the transaction out-of-band (e.g., in the blockchain layer). It provides the necessary information so only the originator and the beneficiary can decrypt the transaction data. For more information about Secure Envelopes, this section of the documentation further describes this primary data structure for the TRISA exchange.
A SecureEnvelope
message contains different types of metadata. The Anatomy of Secure Envelope section of this documentation further describes the envelope metadata, cryptographic metadata, and an encrypted payload and HMAC signature within the SecureEnvelope
.
message SecureEnvelope {
string id = 1;
bytes payload = 2;
bytes encryption_key = 3;
string encryption_algorithm = 4;
bytes hmac = 5;
bytes hmac_secret = 6;
string hmac_algorithm = 7;
Error error = 9;
string timestamp = 10;
bool sealed = 11;
string public_key_signature = 12;
TransferState transfer_state = 13;
New in v1.1: the TransferState
describes the condition of the transfer the sending party feels the Transfer of Travel Rule data is in. This can be optionally used to signal to the counterparty the intent of a transfer message. See TRISA Workflows for more information on how the transfer state works.
enum TransferState {
UNSPECIFIED = 0; // the transfer state is unknown or not specified
STARTED = 1; // this is the first message in the TRISA workflow
PENDING = 2; // action is required by the sending party
REVIEW = 3; // action is required by the receiving party (rarely used)
REPAIR = 4; // some state of the travel rule exchange requires repair
ACCEPTED = 5; // the travel rule exchange is accepted and awaiting the transaction
COMPLETED = 6; // the travel rule and on-chain transaction have been completed
REJECTED = 7; // the travel rule exchange is rejected and should not proceed
}
ConfirmAddress RPC
Address confirmation was initially described in the TRISA whitepaper as a mechanism to allow an originator VASP to establish that a beneficiary VASP has control of a crypto wallet address before sending transaction information with sensitive PII data.
Currently, there are three proposed address confirmation methods being tested: simple, key/token, and on-chain. Simple involves a simple yes/no check with the counterparty. Key/Token requires the counterparty to decrypt a token encrypted with the crypto address public keys, and on-chain implements a simple Satoshi test.
All three methods are available in the protocol buffers, but note that these are still being tested and developed, and may change at any time. No backward compatibility is guaranteed for these message types, nor is there any guarantee that any TRISA VASP will implement any of these confirmation methods.
KeyExchange RPC
The KeyExchange
RPC allows VASPs to exchange public signing keys to facilitate transaction signatures if they have not already obtained them from the directory service.
SigningKey
SigningKey
provides metadata for decoding a PEM encoded PKIX public key for RSA encryption and transaction signing. The SigningKey is a lightweight version of the certificate information stored in the Directory Service.
message SigningKey {
// x.509 metadata for reference without parsing the key
int64 version = 1;
bytes signature = 2;
string signature_algorithm = 3;
string public_key_algorithm = 4;
// Validity information
string not_before = 8;
string not_after = 9;
bool revoked = 10;
// The serialized public key to PKIX, ASN.1 DER form.
bytes data = 11;
}
The TRISAHealth Service and Status RPC
The TRISAHealth
service contains the Status
RPC, which is optional but highly recommended for VASP members to implement. The Status endpoint allows TRISA members and the TRISA Directory Service to perform health checks with a VASP’s TRISA Node and report the service conditions of the TRISA network. Because a down TRISA node will prevent travel rule compliant virtual asset transactions, the health service is intended to quickly identify network problems and notify members as quickly as possible.
The TRISAHealth
service must also be behind mTLS so that the health check service can verify the identity certificates used for the TRISANetwork service.
service TRISAHealth {
rpc Status(HealthCheck) returns (ServiceState) {}
}
HealthCheck
HealthCheck
specifies attempts
, which is the number of failed health checks that proceeded the current check, and last_checked
, which is the timestamp of the last health check, successful or otherwise.
message HealthCheck {
uint32 attempts = 1;
string last_checked_at = 2;
}
ServiceState
ServiceState
returns the status
, which is the Current service status as defined by the receiving system. The system must respond with the closest matching status in a best-effort fashion. Alerts will be triggered on service status changes if the system does not respond and the previous system state was not unknown. not_before
and not_after
are also returned; they suggest to the directory service when to recheck the health status.
message ServiceState {
enum Status {
UNKNOWN = 0;
HEALTHY = 1;
UNHEALTHY = 2;
DANGER = 3;
OFFLINE = 4;
MAINTENANCE = 5;
}
Status status = 1;
// When to check the health status again.
string not_before = 2;
string not_after = 3;
}
TRISA API in Go
The implementation of the TRISA Protocol Buffers in Go is compiled using protoc
when go generate ./...
is executed in the root of the repository. The compiled files in the TRISA repository contain the TRISA Network Protocol implemented in Go.
The TRISANetworkServer
is the server API for TRISANetwork
, while the TRISANetworkClient
is the client API for the TRISANetwork
service. Both contain the Transfer
, TransferStream
, ConfirmAddress
, and KeyExchange
methods described above as RPCs under the TRISANetwork
service.
type TRISANetworkClient interface {
Transfer(ctx context.Context, in *SecureEnvelope, opts ...grpc.CallOption) (*SecureEnvelope, error)
TransferStream(ctx context.Context, opts ...grpc.CallOption) (TRISANetwork_TransferStreamClient, error)
ConfirmAddress(ctx context.Context, in *Address, opts ...grpc.CallOption) (*AddressConfirmation, error)
KeyExchange(ctx context.Context, in *SigningKey, opts ...grpc.CallOption) (*SigningKey, error)
}
type TRISANetworkServer interface {
Transfer(context.Context, *SecureEnvelope) (*SecureEnvelope, error)
TransferStream(TRISANetwork_TransferStreamServer) error
ConfirmAddress(context.Context, *Address) (*AddressConfirmation, error)
KeyExchange(context.Context, *SigningKey) (*SigningKey, error)
}
For further information, a reference implementation of the TRISA Network protocol is available in Go in the TRISA TestNet Repository,