use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
use sha2::{Digest, Sha256};
use thiserror::Error;
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::signing::sign_verified;
use crate::types::{PositionType, TakerSide};
use crate::wire::{WireError, decode_base58_32, decode_base58_64, encode_base58, encode_hex};
use crate::{AsyncSignerLike, SigningError};
pub const ORDER_ID_LEN: usize = 32;
pub const ORDER_DOMAIN_TAG: [u8; 4] = *b"ACTA";
const TAG_LEN: usize = 4;
const CHAIN_ID_LEN: usize = 8;
const PUBKEY_LEN: usize = 32;
const BOOL_LEN: usize = 1;
const U64_LEN: usize = 8;
const HEADER_LEN: usize = TAG_LEN + CHAIN_ID_LEN + PUBKEY_LEN;
const OFF_IS_TAKER_BUY: usize = 0;
const OFF_POSITION_TYPE: usize = OFF_IS_TAKER_BUY + BOOL_LEN;
const OFF_MARKET: usize = OFF_POSITION_TYPE + BOOL_LEN;
const OFF_STRIKE: usize = OFF_MARKET + PUBKEY_LEN;
const OFF_QUANTITY: usize = OFF_STRIKE + U64_LEN;
const OFF_GROSS_PRICE: usize = OFF_QUANTITY + U64_LEN;
const OFF_VALID_UNTIL: usize = OFF_GROSS_PRICE + U64_LEN;
const OFF_MAKER: usize = OFF_VALID_UNTIL + U64_LEN;
const OFF_TAKER: usize = OFF_MAKER + PUBKEY_LEN;
const OFF_NONCE: usize = OFF_TAKER + PUBKEY_LEN;
const _: () = assert!(HEADER_LEN + OFF_NONCE + U64_LEN == ORDER_PREIMAGE_LEN);
pub const ORDER_PREIMAGE_LEN: usize = TAG_LEN
+ CHAIN_ID_LEN
+ PUBKEY_LEN
+ BOOL_LEN
+ BOOL_LEN
+ PUBKEY_LEN
+ U64_LEN
+ U64_LEN
+ U64_LEN
+ U64_LEN
+ PUBKEY_LEN
+ PUBKEY_LEN
+ U64_LEN;
pub trait SignerLike {
fn pubkey_bytes(&self) -> [u8; 32];
fn sign_message(&self, msg: &[u8]) -> [u8; 64];
fn pubkey_base58(&self) -> String {
encode_base58(&self.pubkey_bytes())
}
fn sign_message_base58(&self, msg: &[u8]) -> String {
encode_base58(&self.sign_message(msg))
}
}
#[derive(Clone)]
pub struct BytesSigner {
signing_key: SigningKey,
pubkey: [u8; 32],
}
impl Zeroize for BytesSigner {
fn zeroize(&mut self) {
let _ = std::mem::replace(&mut self.signing_key, SigningKey::from_bytes(&[0u8; 32]));
}
}
impl ZeroizeOnDrop for BytesSigner {}
impl BytesSigner {
pub fn from_secret(mut secret: [u8; 32]) -> Self {
let signing_key = SigningKey::from_bytes(&secret);
let pubkey = signing_key.verifying_key().to_bytes();
secret.zeroize();
Self {
signing_key,
pubkey,
}
}
pub fn from_keypair(keypair: &[u8; 64]) -> Result<Self, OrderError> {
let mut secret = [0u8; 32];
secret.copy_from_slice(&keypair[0..32]);
let signer = Self::from_secret(secret);
secret.zeroize();
if signer.pubkey != keypair[32..64] {
return Err(OrderError::KeypairPublicKeyMismatch);
}
Ok(signer)
}
}
impl SignerLike for BytesSigner {
fn pubkey_bytes(&self) -> [u8; 32] {
self.pubkey
}
fn sign_message(&self, msg: &[u8]) -> [u8; 64] {
let signature: Signature = self.signing_key.sign(msg);
signature.to_bytes()
}
}
#[derive(Debug, Clone)]
pub struct OrderPreimageArgs {
pub chain_id: u64,
pub program_id: [u8; 32],
pub side: TakerSide,
pub position_type: PositionType,
pub market: [u8; 32],
pub strike: u64,
pub quantity: u64,
pub gross_price: u64,
pub valid_until: u64,
pub maker: [u8; 32],
pub taker: [u8; 32],
pub nonce: u64,
}
#[derive(Debug, Error)]
pub enum OrderError {
#[error("spread types require the spread order layout")]
SpreadLayoutRequired,
#[error("keypair public key does not match its secret key")]
KeypairPublicKeyMismatch,
#[error("invalid signing key: {0}")]
InvalidSigningKey(String),
#[error("invalid verifying key: {0}")]
InvalidVerifyingKey(String),
#[error("signature verification failed")]
InvalidSignature,
#[error(transparent)]
Wire(#[from] WireError),
}
pub fn build_order_preimage(
args: &OrderPreimageArgs,
) -> Result<[u8; ORDER_PREIMAGE_LEN], OrderError> {
if args.position_type.is_spread() {
return Err(OrderError::SpreadLayoutRequired);
}
Ok(build_physical_order_preimage(
args,
args.position_type == PositionType::CashSecuredPut,
))
}
pub(crate) fn build_physical_order_preimage(
args: &OrderPreimageArgs,
is_put: bool,
) -> [u8; ORDER_PREIMAGE_LEN] {
let mut buf = [0u8; ORDER_PREIMAGE_LEN];
buf[0..TAG_LEN].copy_from_slice(&ORDER_DOMAIN_TAG);
buf[TAG_LEN..TAG_LEN + CHAIN_ID_LEN].copy_from_slice(&args.chain_id.to_le_bytes());
buf[TAG_LEN + CHAIN_ID_LEN..HEADER_LEN].copy_from_slice(&args.program_id);
let b = HEADER_LEN;
buf[b + OFF_IS_TAKER_BUY] = u8::from(args.side.is_taker_buy());
buf[b + OFF_POSITION_TYPE] = u8::from(is_put);
buf[b + OFF_MARKET..b + OFF_MARKET + PUBKEY_LEN].copy_from_slice(&args.market);
buf[b + OFF_STRIKE..b + OFF_STRIKE + U64_LEN].copy_from_slice(&args.strike.to_le_bytes());
buf[b + OFF_QUANTITY..b + OFF_QUANTITY + U64_LEN].copy_from_slice(&args.quantity.to_le_bytes());
buf[b + OFF_GROSS_PRICE..b + OFF_GROSS_PRICE + U64_LEN]
.copy_from_slice(&args.gross_price.to_le_bytes());
buf[b + OFF_VALID_UNTIL..b + OFF_VALID_UNTIL + U64_LEN]
.copy_from_slice(&args.valid_until.to_le_bytes());
buf[b + OFF_MAKER..b + OFF_MAKER + PUBKEY_LEN].copy_from_slice(&args.maker);
buf[b + OFF_TAKER..b + OFF_TAKER + PUBKEY_LEN].copy_from_slice(&args.taker);
buf[b + OFF_NONCE..b + OFF_NONCE + U64_LEN].copy_from_slice(&args.nonce.to_le_bytes());
buf
}
pub fn hash_order_preimage(preimage: &[u8; ORDER_PREIMAGE_LEN]) -> [u8; ORDER_ID_LEN] {
let digest = Sha256::digest(preimage);
digest.into()
}
pub fn compute_order_id(args: &OrderPreimageArgs) -> Result<[u8; ORDER_ID_LEN], OrderError> {
Ok(hash_order_preimage(&build_order_preimage(args)?))
}
pub fn order_id_hex(order_id: &[u8; ORDER_ID_LEN]) -> String {
encode_hex(order_id)
}
pub fn order_preimage_hex(preimage: &[u8; ORDER_PREIMAGE_LEN]) -> String {
encode_hex(preimage)
}
pub fn sign_order_id_bytes(
order_id: &[u8; ORDER_ID_LEN],
signing_key_bytes: &[u8; 32],
) -> Result<[u8; 64], OrderError> {
let signing_key = SigningKey::from_bytes(signing_key_bytes);
let signature: Signature = signing_key.sign(order_id);
Ok(signature.to_bytes())
}
pub fn sign_order_id_base58(
order_id: &[u8; ORDER_ID_LEN],
signing_key_bytes: &[u8; 32],
) -> Result<String, OrderError> {
let sig = sign_order_id_bytes(order_id, signing_key_bytes)?;
Ok(encode_base58(&sig))
}
pub fn sign_order_id_with_signer<S: SignerLike + ?Sized>(
order_id: &[u8; ORDER_ID_LEN],
signer: &S,
) -> [u8; 64] {
signer.sign_message(order_id)
}
pub fn sign_order_id_with_signer_base58<S: SignerLike>(
order_id: &[u8; ORDER_ID_LEN],
signer: &S,
) -> String {
signer.sign_message_base58(order_id)
}
pub async fn sign_order_id_with_async_signer<S: AsyncSignerLike + ?Sized>(
order_id: &[u8; ORDER_ID_LEN],
signer: &S,
) -> Result<[u8; 64], SigningError> {
sign_verified(signer, order_id).await
}
pub fn verify_order_id_signature_bytes(
order_id: &[u8; ORDER_ID_LEN],
signature: &[u8; 64],
verifying_key_bytes: &[u8; 32],
) -> Result<(), OrderError> {
let verifying_key = VerifyingKey::from_bytes(verifying_key_bytes)
.map_err(|err| OrderError::InvalidVerifyingKey(err.to_string()))?;
let signature = Signature::from_bytes(signature);
verifying_key
.verify(order_id, &signature)
.map_err(|_| OrderError::InvalidSignature)
}
pub fn verify_order_id_signature_base58(
order_id_hex: &str,
signature_base58: &str,
pubkey_base58: &str,
) -> Result<(), OrderError> {
let order_id = decode_hex32(order_id_hex)?;
let signature = decode_base58_64(signature_base58)?;
let pubkey = decode_base58_32(pubkey_base58)?;
verify_order_id_signature_bytes(&order_id, &signature, &pubkey)
}
pub fn sign_order_id_from_base58_keypair(
order_id_hex: &str,
keypair_base58: &str,
) -> Result<String, OrderError> {
let order_id = decode_hex32(order_id_hex)?;
let keypair = decode_base58_64(keypair_base58)?;
let signer = BytesSigner::from_keypair(&keypair)?;
Ok(sign_order_id_with_signer_base58(&order_id, &signer))
}
fn decode_hex32(hex_str: &str) -> Result<[u8; 32], OrderError> {
crate::wire::decode_hex_32(hex_str).map_err(OrderError::Wire)
}
mod spreads;
pub use spreads::*;