use crate::{
error::Error,
event::sections::key_config::nxt_commitment,
event::{
event_data::{
delegated::DelegatedInceptionEvent, interaction::InteractionEvent,
rotation::RotationEvent,
},
sections::{
key_config::NextKeysData, threshold::SignatureThreshold, RotationWitnessConfig,
},
},
event::{
event_data::{inception::InceptionEvent, EventData},
receipt::Receipt,
sections::seal::Seal,
sections::InceptionWitnessConfig,
sections::KeyConfig,
KeyEvent,
},
keys::PublicKey,
prefix::{BasicPrefix, IdentifierPrefix},
};
use ed25519_dalek::SigningKey;
use rand::rngs::OsRng;
use said::version::format::SerializationFormats;
use said::{
derivation::{HashFunction, HashFunctionCode},
SelfAddressingIdentifier,
};
use super::{msg::KeriEvent, EventTypeTag};
pub struct EventMsgBuilder {
event_type: EventTypeTag,
prefix: IdentifierPrefix,
sn: u64,
key_threshold: SignatureThreshold,
next_key_threshold: SignatureThreshold,
keys: Vec<BasicPrefix>,
next_keys: Vec<BasicPrefix>,
next_keys_hashes: Option<Vec<SelfAddressingIdentifier>>,
prev_event: SelfAddressingIdentifier,
data: Vec<Seal>,
delegator: IdentifierPrefix,
witness_threshold: SignatureThreshold,
witnesses: Vec<BasicPrefix>,
witness_to_add: Vec<BasicPrefix>,
witness_to_remove: Vec<BasicPrefix>,
format: SerializationFormats,
derivation: HashFunction,
}
impl EventMsgBuilder {
pub fn new(event_type: EventTypeTag) -> Self {
let mut rng = OsRng {};
let kp = SigningKey::generate(&mut rng);
let nkp = SigningKey::generate(&mut rng);
let pk = PublicKey::new(kp.verifying_key().to_bytes().to_vec());
let npk = PublicKey::new(nkp.verifying_key().to_bytes().to_vec());
let hash_function: HashFunction = HashFunctionCode::Blake3_256.into();
let basic_pref = BasicPrefix::Ed25519(pk);
EventMsgBuilder {
event_type,
prefix: IdentifierPrefix::default(),
keys: vec![basic_pref],
next_keys: vec![BasicPrefix::Ed25519(npk)],
key_threshold: SignatureThreshold::default(),
next_key_threshold: SignatureThreshold::default(),
sn: 1,
prev_event: hash_function.derive(&[0u8; 32]),
data: vec![],
delegator: IdentifierPrefix::default(),
witness_threshold: SignatureThreshold::Simple(0),
witnesses: vec![],
witness_to_add: vec![],
witness_to_remove: vec![],
format: SerializationFormats::JSON,
derivation: hash_function,
next_keys_hashes: None,
}
}
pub fn with_prefix(self, prefix: &IdentifierPrefix) -> Self {
EventMsgBuilder {
prefix: prefix.clone(),
..self
}
}
pub fn with_keys(self, keys: Vec<BasicPrefix>) -> Self {
EventMsgBuilder { keys, ..self }
}
pub fn with_next_keys(self, next_keys: Vec<BasicPrefix>) -> Self {
EventMsgBuilder { next_keys, ..self }
}
pub fn with_next_keys_hashes(self, next_keys: Vec<SelfAddressingIdentifier>) -> Self {
EventMsgBuilder {
next_keys_hashes: Some(next_keys),
..self
}
}
pub fn with_sn(self, sn: u64) -> Self {
EventMsgBuilder { sn, ..self }
}
pub fn with_previous_event(self, prev_event: &SelfAddressingIdentifier) -> Self {
EventMsgBuilder {
prev_event: prev_event.clone(),
..self
}
}
pub fn with_seal(mut self, seals: Vec<Seal>) -> Self {
self.data.extend(seals);
EventMsgBuilder { ..self }
}
pub fn with_delegator(self, delegator: &IdentifierPrefix) -> Self {
EventMsgBuilder {
delegator: delegator.clone(),
..self
}
}
pub fn with_threshold(self, threshold: &SignatureThreshold) -> Self {
EventMsgBuilder {
key_threshold: threshold.clone(),
..self
}
}
pub fn with_next_threshold(self, threshold: &SignatureThreshold) -> Self {
EventMsgBuilder {
next_key_threshold: threshold.clone(),
..self
}
}
pub fn with_witness_list(self, witnesses: &[BasicPrefix]) -> Self {
EventMsgBuilder {
witnesses: witnesses.to_vec(),
..self
}
}
pub fn with_witness_to_add(self, witness_to_add: &[BasicPrefix]) -> Self {
EventMsgBuilder {
witness_to_add: witness_to_add.to_vec(),
..self
}
}
pub fn with_witness_to_remove(self, witness_to_remove: &[BasicPrefix]) -> Self {
EventMsgBuilder {
witness_to_remove: witness_to_remove.to_vec(),
..self
}
}
pub fn with_witness_threshold(self, witness_threshold: &SignatureThreshold) -> Self {
EventMsgBuilder {
witness_threshold: witness_threshold.clone(),
..self
}
}
pub fn build(self) -> Result<KeriEvent<KeyEvent>, Error> {
let next_key_hash = if let Some(hashes) = self.next_keys_hashes {
NextKeysData::new(self.next_key_threshold, hashes)
} else {
nxt_commitment(self.next_key_threshold, &self.next_keys, &self.derivation)
};
let key_config = KeyConfig::new(self.keys, next_key_hash, Some(self.key_threshold));
let prefix = if self.prefix == IdentifierPrefix::default() {
let icp_data = InceptionEvent::new(key_config.clone(), None, None)
.incept_self_addressing(self.derivation.clone(), self.format)?;
icp_data.data.get_prefix()
} else {
self.prefix
};
Ok(match self.event_type {
EventTypeTag::Icp => {
let icp_event = InceptionEvent {
key_config,
witness_config: InceptionWitnessConfig {
tally: self.witness_threshold,
initial_witnesses: self.witnesses,
},
inception_configuration: vec![],
data: vec![],
};
match prefix {
IdentifierPrefix::Basic(_) => {
KeyEvent::new(prefix, 0, EventData::Icp(icp_event))
.to_message(self.format, self.derivation)?
}
IdentifierPrefix::SelfAddressing(_) => {
icp_event.incept_self_addressing(self.derivation, self.format)?
}
_ => todo!(),
}
}
EventTypeTag::Rot => KeyEvent::new(
prefix,
self.sn,
EventData::Rot(RotationEvent::new(
self.prev_event,
key_config,
RotationWitnessConfig {
tally: self.witness_threshold,
prune: self.witness_to_remove,
graft: self.witness_to_add,
},
self.data,
)),
)
.to_message(self.format, self.derivation)?,
EventTypeTag::Ixn => KeyEvent::new(
prefix,
self.sn,
EventData::Ixn(InteractionEvent::new(self.prev_event.into(), self.data)),
)
.to_message(self.format, self.derivation)?,
EventTypeTag::Dip => {
let icp_data = InceptionEvent {
key_config,
witness_config: InceptionWitnessConfig {
tally: self.witness_threshold,
initial_witnesses: self.witnesses,
},
inception_configuration: vec![],
data: vec![],
};
DelegatedInceptionEvent {
inception_data: icp_data,
delegator: self.delegator,
}
.incept_self_addressing(self.derivation, self.format)?
}
EventTypeTag::Drt => {
let rotation_data = RotationEvent::new(
self.prev_event,
key_config,
RotationWitnessConfig::default(),
self.data,
);
KeyEvent::new(prefix, self.sn, EventData::Drt(rotation_data))
.to_message(self.format, self.derivation)?
}
_ => return Err(Error::SemanticError("Not key event".into())),
})
}
}
pub struct ReceiptBuilder {
format: SerializationFormats,
receipted_event: KeriEvent<KeyEvent>,
}
impl Default for ReceiptBuilder {
fn default() -> Self {
let default_event = EventMsgBuilder::new(EventTypeTag::Icp).build().unwrap();
Self {
format: SerializationFormats::JSON,
receipted_event: default_event,
}
}
}
impl ReceiptBuilder {
pub fn with_format(self, format: SerializationFormats) -> Self {
Self { format, ..self }
}
pub fn with_receipted_event(self, receipted_event: KeriEvent<KeyEvent>) -> Self {
Self {
receipted_event,
..self
}
}
pub fn build(&self) -> Result<Receipt, Error> {
let prefix = self.receipted_event.data.get_prefix();
let sn = self.receipted_event.data.get_sn();
let receipted_event_digest = self.receipted_event.digest()?;
Ok(Receipt::new(
self.format,
receipted_event_digest,
prefix,
sn,
))
}
}
#[test]
fn test_multisig_prefix_derivation() {
// Keys taken from keripy: keripy/tests/core/test_eventing.py::test_multisig_digprefix (line 2255)
let expected_event = br#"{"v":"KERI10JSON0001e7_","t":"icp","d":"EBfxc4RiVY6saIFmUfEtETs1FcqmktZW88UkbnOg0Qen","i":"EBfxc4RiVY6saIFmUfEtETs1FcqmktZW88UkbnOg0Qen","s":"0","kt":"2","k":["DErocgXD2RGSyvn3MObcx59jeOsEQhv2TqHirVkzrp0Q","DFXLiTjiRdSBPLL6hLa0rskIxk3dh4XwJLfctkJFLRSS","DE9YgIQVgpLwocTVrG8tidKScsQSMWwLWywNC48fhq4f"],"nt":"2","n":["EDJk5EEpC4-tQ7YDwBiKbpaZahh1QCyQOnZRF7p2i8k8","EAXfDjKvUFRj-IEB_o4y-Y_qeJAjYfZtOMD9e7vHNFss","EN8l6yJC2PxribTN0xfri6bLz34Qvj-x3cNwcV3DvT2m"],"bt":"0","b":[],"c":[],"a":[]}"#;
let keys: Vec<BasicPrefix> = vec![
"DErocgXD2RGSyvn3MObcx59jeOsEQhv2TqHirVkzrp0Q"
.parse()
.unwrap(),
"DFXLiTjiRdSBPLL6hLa0rskIxk3dh4XwJLfctkJFLRSS"
.parse()
.unwrap(),
"DE9YgIQVgpLwocTVrG8tidKScsQSMWwLWywNC48fhq4f"
.parse()
.unwrap(),
];
let next_keys: Vec<BasicPrefix> = vec![
"DCjxOXniUc5EUzDqERlXdptfKPHy6jNo_ZGsS4Vd8fAE"
.parse()
.unwrap(),
"DNZHARO4dCJlluv0qezEMRmErIWWc-lzOzolBOQ15tHV"
.parse()
.unwrap(),
"DOCQ4KN1jUlKbfjRteDYt9fxgpq1NK9_MqO5IA7shpED"
.parse()
.unwrap(),
];
let msg_builder = EventMsgBuilder::new(EventTypeTag::Icp)
.with_keys(keys)
.with_next_keys(next_keys)
.with_threshold(&SignatureThreshold::Simple(2))
.with_next_threshold(&SignatureThreshold::Simple(2));
let msg = msg_builder.build().unwrap();
assert_eq!(expected_event.to_vec(), msg.encode().unwrap());
}