Las entidades bancarias son responsables de almacenar y gestionar sus propios Keepers.

Los Keepers se utilizan para generar Signers y firmar Actions de forma offline.

Una vez firmado, el Action debe enviarse al núcleo de TIN Cloud utilizando el endpoint:

POST /v1/action/:action_id/sendit

  • Si el Action firmado es aceptado por TIN Cloud, recibirá labels.status: COMPLETED y un valor en labels.hash.
  • Si es rechazado, el estado será labels.status: REJECTED y labels.hash tendrá el valor none.

Firmar Action offline

Los Keepers deben cargarse desde el sistema de gestión de llaves (KMS) antes de firmar un Action.

Para firmar un Action, necesitas su action_id y el Keeper correspondiente a Action.source.

💻 Código de ejemplo en Java

import java.security.MessageDigest;
import java.security.Signature;

import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.Utils;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;

public class SignatureUtil {
    public static String OfflineSigning(String claimsHash, String secretKey) {
        try {
            // Convert private key to EdDSAPrivateKey
            EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
            EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(Utils.hexToBytes(secretKey), ed25519);
            EdDSAPrivateKey privateKey = new EdDSAPrivateKey(keySpec);

            // Sign the hash
            EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
            Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
            sgr.initSign(privateKey);
            sgr.update(Utils.hexToBytes(claimsHash));
            byte[] signature = sgr.sign();

            // Convert signature to hex string
            return Utils.bytesToHex(signature);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
package minka.crypto.dtos;

import java.security.KeyPair;

import net.i2p.crypto.eddsa.KeyPairGenerator;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.Utils;

public class KeeperDto {
    private String publicKey;
    private String secretKey;
    private String scheme = "eddsa-ed25519";

    public KeeperDto(String publicKey, String secretKey) {
        this.publicKey = publicKey;
        this.secretKey = secretKey;
    }

    public static KeeperDto GenerateKeys() {
        KeyPairGenerator keyPairGenerator = new KeyPairGenerator();
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        EdDSAPublicKey publicKey = (EdDSAPublicKey) keyPair.getPublic();
        EdDSAPrivateKey secretKey = (EdDSAPrivateKey) keyPair.getPrivate();

        String publicKeyHexStr = Utils.bytesToHex(publicKey.getA().toByteArray());
        String secretKeyHexStr = Utils.bytesToHex(secretKey.getSeed());

        return new KeeperDto(publicKeyHexStr, secretKeyHexStr);
    }
}

Ejemplo C##

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Utilities.Encoders;

namespace Keeper {
    public class SignatureDto
    {
        private List<Signatures> signatures;

        public SignatureDto(HashDto hashDto, string address, string publicKey, string secretKey)
        {
            var decodedPrivateBytes = Hex.Decode(secretKey);
            var ed25519PrivateKeyParameters = new Ed25519PrivateKeyParameters(decodedPrivateBytes, 0);

            var ed25519Signer = new Ed25519Signer();
            ed25519Signer.Init(true, ed25519PrivateKeyParameters);
            byte[] msg = Hex.Decode(hashDto.Value);
            ed25519Signer.BlockUpdate(msg, 0, msg.Length);
            var signature = ed25519Signer.GenerateSignature();
            var signatureHexString = Hex.ToHexString(signature);

            List<Signatures> theSignatures = new List<Signatures>();
            Signatures oneSignature = new Signatures();
            oneSignature.Scheme = "eddsa-ed25519";
            oneSignature.String = signatureHexString;
            oneSignature.Signer = address;
            oneSignature.Public = publicKey;

            theSignatures.Add(oneSignature);
            this.signatures = theSignatures;
        }

        public List<Signatures> Signatures
        {
            get => signatures;
            set => signatures = value;
        }
    }
}

Ejemplo Node JSON

const crypto = require('crypto')
const elliptic = require('elliptic')
const eddsa25519 = new elliptic.eddsa('ed25519')

const getClaims = () => {
  const date = new Date()
  return {
    source: 'source-address',
    symbol: 'symbol-address',
    target: 'target-address',
    amount: '1000',
    domain: 'tin',
    expiry: date.toISOString(),
  }
}

function signIOU(claims, privateKey) {
  let eddsaKeyPair = eddsa25519.keyFromSecret(privateKey)
  let signature = eddsaKeyPair.sign(claims)
  return signature.toHex()
}