use core::fmt;
use crate::crypto::{key_id, SecretKey};
use crate::error::Result;
use crate::json::Value;
use crate::lexical::to_hex;
use crate::model::{args_to_value, Args, Cell, Scalar};
use crate::receipt::Receipt;
#[derive(Clone)]
pub struct SigningKey {
secret: SecretKey,
key_id: String,
}
impl SigningKey {
pub fn from_seed(seed: &[u8; 32]) -> SigningKey {
let secret = SecretKey::from_seed(seed);
let key_id = key_id(&secret.public);
SigningKey { secret, key_id }
}
pub fn public_key(&self) -> [u8; 32] {
self.secret.public
}
pub fn key_id(&self) -> &str {
&self.key_id
}
}
impl fmt::Debug for SigningKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SigningKey").field("key_id", &self.key_id).finish_non_exhaustive()
}
}
#[derive(Clone, Debug, Default)]
pub struct ReceiptBuilder {
cell: Option<Cell>,
value: Option<Scalar>,
valid: Option<Args>,
asof: Option<String>,
tx: Option<String>,
issued: Option<String>,
publisher: Option<String>,
signer_host: Option<String>,
inputs: Vec<String>,
licence: Option<String>,
summary: Option<String>,
}
impl ReceiptBuilder {
pub fn new() -> ReceiptBuilder {
ReceiptBuilder::default()
}
pub fn cell(mut self, cell: Cell) -> Self {
self.cell = Some(cell);
self
}
pub fn value(mut self, value: Scalar) -> Self {
self.value = Some(value);
self
}
pub fn valid(mut self, valid: Args) -> Self {
self.valid = Some(valid);
self
}
pub fn asof(mut self, asof: impl Into<String>) -> Self {
self.asof = Some(asof.into());
self
}
pub fn tx(mut self, tx: impl Into<String>) -> Self {
self.tx = Some(tx.into());
self
}
pub fn issued(mut self, issued: impl Into<String>) -> Self {
self.issued = Some(issued.into());
self
}
pub fn publisher(mut self, publisher: impl Into<String>) -> Self {
self.publisher = Some(publisher.into());
self
}
pub fn signer_host(mut self, host: impl Into<String>) -> Self {
self.signer_host = Some(host.into());
self
}
pub fn inputs<I, S>(mut self, inputs: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.inputs = inputs.into_iter().map(Into::into).collect();
self
}
pub fn licence(mut self, licence: impl Into<String>) -> Self {
self.licence = Some(licence.into());
self
}
pub fn summary(mut self, summary: impl Into<String>) -> Self {
self.summary = Some(summary.into());
self
}
pub fn sign(&self, key: &SigningKey) -> Result<Receipt> {
let s = |x: &Option<String>| x.as_ref().map(|t| Value::String(t.clone()));
let computed_by = self.signer_host.as_ref().map(|h| Value::String(format!("{h}#{}", key.key_id())));
let (ty, value) = match &self.value {
Some(v) => {
let raw = match v {
Scalar::Boolean(b) => Value::Bool(*b),
other => Value::String(other.lexical().to_string()),
};
(Some(Value::String(v.ty().as_str().into())), Some(raw))
}
None => (None, None),
};
let placeholder = "0".repeat(128);
let members: Vec<(&str, Option<Value>)> = vec![
("asof", s(&self.asof)),
("cell", self.cell.as_ref().map(Cell::to_value)),
("computed_by", computed_by),
("inputs", Some(Value::Array(self.inputs.iter().map(|h| Value::String(h.clone())).collect()))),
("issued", s(&self.issued)),
("licence", s(&self.licence)),
("proto", Some(Value::String("datumesh/1".into()))),
("publisher", s(&self.publisher)),
("sig", Some(Value::String(placeholder))),
("summary", s(&self.summary)),
("tx", s(&self.tx)),
("type", ty),
("valid", self.valid.as_ref().map(args_to_value)),
("value", value),
];
let object = members.into_iter().filter_map(|(k, v)| v.map(|v| (k.to_string(), v))).collect();
let unsigned = Receipt::from_value(&Value::Object(object))?;
let sig = key.secret.sign(unsigned.payload());
Ok(unsigned.with_sig(to_hex(&sig)))
}
}