import io.brane.core.crypto.Signer;
import io.brane.core.crypto.Signature;
import io.brane.core.types.Address;
import io.brane.core.tx.UnsignedTransaction;
import io.brane.core.crypto.Keccak256;
// Dummy interface for the example
interface ExternalService {
Signature sign(String keyId, byte[] hash);
}
public class RemoteSigner implements Signer {
private final String keyId;
private final Address address;
private final ExternalService service;
public RemoteSigner(String keyId, Address address, ExternalService service) {
this.keyId = keyId;
this.address = address;
this.service = service;
}
@Override
public Address address() {
return address;
}
@Override
public Signature signTransaction(UnsignedTransaction tx, long chainId) {
// 1. Get the transaction hash (preimage)
byte[] preimage = tx.encodeForSigning(chainId);
byte[] hash = Keccak256.hash(preimage);
// 2. Request signature from external service
// (This is where you call Privy, AWS KMS, etc.)
return service.sign(this.keyId, hash);
}
@Override
public Signature signMessage(byte[] message) {
// 1. Create the EIP-191 prefixed message
byte[] prefix = ("\u0019Ethereum Signed Message:\n" + message.length)
.getBytes(java.nio.charset.StandardCharsets.UTF_8);
byte[] prefixedMessage = java.nio.ByteBuffer.allocate(prefix.length + message.length)
.put(prefix)
.put(message)
.array();
// 2. Hash the prefixed message
byte[] hash = Keccak256.hash(prefixedMessage);
// 3. Request signature for the hash
Signature sig = service.sign(this.keyId, hash);
// Adjust v to be 27 or 28 for EIP-191 compatibility
return new Signature(sig.r(), sig.s(), sig.v() + 27);
}
}