1use crate::ser_impls::{
4 read_as_tlv, read_i32, read_schnorr_pubkey, read_schnorrsig, read_strings_u16, write_as_tlv,
5 write_i32, write_schnorr_pubkey, write_schnorrsig, write_strings_u16, BigSize,
6};
7use bitcoin::hashes::{Hash, HashEngine};
8use ddk_dlc::{Error, OracleInfo as DlcOracleInfo};
9use lightning::ln::msgs::DecodeError;
10use lightning::ln::wire::Type;
11use lightning::util::ser::{Readable, Writeable, Writer};
12use secp256k1_zkp::Verification;
13use secp256k1_zkp::{schnorr::Signature, Message, Secp256k1, XOnlyPublicKey};
14#[cfg(feature = "use-serde")]
15use serde::{Deserialize, Serialize};
16
17pub const ANNOUNCEMENT_TYPE: u16 = 55332;
19pub const ATTESTATION_TYPE: u16 = 55400;
21
22pub const ORACLE_ANNOUNCEMENT_TAG: &[u8] = b"DLC/oracle/announcement/v0";
24pub const ORACLE_ATTESTATION_TAG: &[u8] = b"DLC/oracle/attestation/v0";
26
27#[derive(Clone, Eq, PartialEq, Debug)]
28#[cfg_attr(
29 feature = "use-serde",
30 derive(serde::Serialize, serde::Deserialize),
31 serde(rename_all = "camelCase")
32)]
33pub enum OracleInfo {
35 Single(SingleOracleInfo),
37 Multi(MultiOracleInfo),
39}
40
41impl<'a> OracleInfo {
42 pub fn get_first_event_descriptor(&'a self) -> &'a EventDescriptor {
44 match self {
45 OracleInfo::Single(single) => &single.oracle_announcement.oracle_event.event_descriptor,
46 OracleInfo::Multi(multi) => {
47 &multi.oracle_announcements[0].oracle_event.event_descriptor
48 }
49 }
50 }
51}
52
53impl OracleInfo {
54 pub fn get_closest_maturity_date(&self) -> u32 {
56 match self {
57 OracleInfo::Single(s) => s.oracle_announcement.oracle_event.event_maturity_epoch,
58 OracleInfo::Multi(m) => m
59 .oracle_announcements
60 .iter()
61 .map(|x| x.oracle_event.event_maturity_epoch)
62 .min()
63 .expect("to have at least one event"),
64 }
65 }
66
67 pub fn validate<C: Verification>(&self, secp: &Secp256k1<C>) -> Result<(), Error> {
69 match self {
70 OracleInfo::Single(s) => s.oracle_announcement.validate(secp)?,
71 OracleInfo::Multi(m) => {
72 for o in &m.oracle_announcements {
73 o.validate(secp)?;
74 }
75 }
76 };
77
78 Ok(())
79 }
80}
81
82impl_dlc_writeable_enum!(
83 OracleInfo, (0, Single), (1, Multi);;;
84);
85
86#[derive(Clone, Eq, PartialEq, Debug)]
87#[cfg_attr(
88 feature = "use-serde",
89 derive(serde::Serialize, serde::Deserialize),
90 serde(rename_all = "camelCase")
91)]
92pub struct SingleOracleInfo {
95 pub oracle_announcement: OracleAnnouncement,
97}
98
99impl_dlc_writeable!(SingleOracleInfo, {
100 (oracle_announcement, {cb_writeable, write_as_tlv, read_as_tlv })
101});
102
103#[derive(Clone, Eq, PartialEq, Debug)]
104#[cfg_attr(
105 feature = "use-serde",
106 derive(serde::Serialize, serde::Deserialize),
107 serde(rename_all = "camelCase")
108)]
109pub struct MultiOracleInfo {
111 pub threshold: u16,
113 pub oracle_announcements: Vec<OracleAnnouncement>,
115 pub oracle_params: Option<OracleParams>,
118}
119
120impl_dlc_writeable!(MultiOracleInfo, {
121 (threshold, writeable),
122 (oracle_announcements, {vec_cb, write_as_tlv, read_as_tlv}),
123 (oracle_params, option)
124});
125
126#[derive(Clone, Eq, PartialEq, Debug)]
127#[cfg_attr(
128 feature = "use-serde",
129 derive(serde::Serialize, serde::Deserialize),
130 serde(rename_all = "camelCase")
131)]
132pub struct OracleParams {
135 pub max_error_exp: u16,
137 pub min_fail_exp: u16,
140 pub maximize_coverage: bool,
143}
144
145impl_dlc_writeable!(OracleParams, {
146 (max_error_exp, writeable),
147 (min_fail_exp, writeable),
148 (maximize_coverage, writeable)
149});
150
151#[derive(Clone, Eq, PartialEq, Debug)]
152#[cfg_attr(
153 feature = "use-serde",
154 derive(Serialize, Deserialize),
155 serde(rename_all = "camelCase")
156)]
157pub struct OracleAnnouncement {
160 pub announcement_signature: Signature,
162 pub oracle_public_key: XOnlyPublicKey,
164 pub oracle_event: OracleEvent,
166}
167
168impl Type for OracleAnnouncement {
169 fn type_id(&self) -> u16 {
170 ANNOUNCEMENT_TYPE
171 }
172}
173
174fn write_oracle_event(event: &OracleEvent) -> Result<Vec<u8>, lightning::io::Error> {
182 let mut event_hex = Vec::new();
183 BigSize(event.type_id() as u64).write(&mut event_hex)?;
184 BigSize(event.serialized_length() as u64).write(&mut event_hex)?;
185 event
186 .write(&mut event_hex)
187 .expect("Error writing oracle event");
188 Ok(event_hex)
189}
190
191pub fn tagged_announcement_msg(event: &OracleEvent) -> Message {
195 let tag_hash = bitcoin::hashes::sha256::Hash::hash(ORACLE_ANNOUNCEMENT_TAG);
196 let event_hex = write_oracle_event(event).expect("Error writing oracle event");
197 let mut hash_engine = bitcoin::hashes::sha256::Hash::engine();
198 hash_engine.input(&tag_hash[..]);
199 hash_engine.input(&tag_hash[..]);
200 hash_engine.input(&event_hex);
201 let hash = bitcoin::hashes::sha256::Hash::from_engine(hash_engine);
202 Message::from_digest(hash.to_byte_array())
203}
204
205pub fn tagged_attestation_msg(outcome: &str) -> Message {
209 let tag_hash = bitcoin::hashes::sha256::Hash::hash(ORACLE_ATTESTATION_TAG);
210 let mut hash_engine = bitcoin::hashes::sha256::Hash::engine();
211 hash_engine.input(&tag_hash[..]);
212 hash_engine.input(&tag_hash[..]);
213 hash_engine.input(outcome.as_bytes());
214 let hash = bitcoin::hashes::sha256::Hash::from_engine(hash_engine);
215 Message::from_digest(hash.to_byte_array())
216}
217
218impl OracleAnnouncement {
219 pub fn validate<C: Verification>(&self, secp: &Secp256k1<C>) -> Result<(), Error> {
221 let msg = tagged_announcement_msg(&self.oracle_event);
222 secp.verify_schnorr(&self.announcement_signature, &msg, &self.oracle_public_key)?;
223 self.oracle_event.validate()
224 }
225}
226
227impl_dlc_writeable!(OracleAnnouncement, {
228 (announcement_signature, {cb_writeable, write_schnorrsig, read_schnorrsig}),
229 (oracle_public_key, {cb_writeable, write_schnorr_pubkey, read_schnorr_pubkey}),
230 (oracle_event, {cb_writeable, write_as_tlv, read_as_tlv})
231});
232
233impl From<&OracleAnnouncement> for DlcOracleInfo {
234 fn from(input: &OracleAnnouncement) -> DlcOracleInfo {
235 DlcOracleInfo {
236 public_key: input.oracle_public_key,
237 nonces: input.oracle_event.oracle_nonces.clone(),
238 }
239 }
240}
241
242#[derive(Clone, Eq, PartialEq, Debug)]
243#[cfg_attr(
244 feature = "use-serde",
245 derive(Serialize, Deserialize),
246 serde(rename_all = "camelCase")
247)]
248pub struct OracleEvent {
250 pub oracle_nonces: Vec<XOnlyPublicKey>,
252 pub event_maturity_epoch: u32,
255 pub event_descriptor: EventDescriptor,
257 pub event_id: String,
259}
260
261impl OracleEvent {
262 pub fn validate(&self) -> Result<(), Error> {
264 let expected_nb_nonces = match &self.event_descriptor {
265 EventDescriptor::EnumEvent(_) => 1,
266 EventDescriptor::DigitDecompositionEvent(d) => {
267 if d.is_signed {
268 d.nb_digits as usize + 1
269 } else {
270 d.nb_digits as usize
271 }
272 }
273 };
274
275 if expected_nb_nonces == self.oracle_nonces.len() {
276 Ok(())
277 } else {
278 Err(Error::InvalidArgument)
279 }
280 }
281}
282
283impl Type for OracleEvent {
284 fn type_id(&self) -> u16 {
285 55330
286 }
287}
288
289impl_dlc_writeable!(OracleEvent, {
290 (oracle_nonces, {vec_u16_cb, write_schnorr_pubkey, read_schnorr_pubkey}),
291 (event_maturity_epoch, writeable),
292 (event_descriptor, writeable),
293 (event_id, string)
294});
295
296#[derive(Clone, PartialEq, Eq, Debug)]
297#[cfg_attr(
298 feature = "use-serde",
299 derive(Serialize, Deserialize),
300 serde(rename_all = "camelCase")
301)]
302pub enum EventDescriptor {
304 EnumEvent(EnumEventDescriptor),
306 DigitDecompositionEvent(DigitDecompositionEventDescriptor),
308}
309
310impl_dlc_writeable_enum_as_tlv!(EventDescriptor, (55302, EnumEvent), (55306, DigitDecompositionEvent););
311
312#[derive(Clone, PartialEq, Eq, Debug)]
313#[cfg_attr(
314 feature = "use-serde",
315 derive(Serialize, Deserialize),
316 serde(rename_all = "camelCase")
317)]
318pub struct EnumEventDescriptor {
320 pub outcomes: Vec<String>,
322}
323
324impl_dlc_writeable!(EnumEventDescriptor, {
325 (outcomes, {cb_writeable, write_strings_u16, read_strings_u16})
326});
327
328#[derive(Clone, PartialEq, Eq, Debug)]
329#[cfg_attr(
330 feature = "use-serde",
331 derive(Serialize, Deserialize),
332 serde(rename_all = "camelCase")
333)]
334pub struct DigitDecompositionEventDescriptor {
336 pub base: u16,
338 pub is_signed: bool,
340 pub unit: String,
342 pub precision: i32,
344 pub nb_digits: u16,
347}
348
349impl_dlc_writeable!(DigitDecompositionEventDescriptor, {
350 (base, writeable),
351 (is_signed, writeable),
352 (unit, string),
353 (precision, {cb_writeable, write_i32, read_i32}),
354 (nb_digits, writeable)
355});
356
357#[derive(Clone, Debug, PartialEq, Eq)]
359#[cfg_attr(
360 feature = "use-serde",
361 derive(Serialize, Deserialize),
362 serde(rename_all = "camelCase")
363)]
364pub struct OracleAttestation {
365 pub event_id: String,
367 pub oracle_public_key: XOnlyPublicKey,
369 pub signatures: Vec<Signature>,
371 pub outcomes: Vec<String>,
373}
374
375impl OracleAttestation {
376 pub fn validate<C: Verification>(
378 &self,
379 secp: &Secp256k1<C>,
380 announcement: &OracleAnnouncement,
381 ) -> Result<(), Error> {
382 if self.outcomes.len() != self.signatures.len() {
383 return Err(Error::InvalidArgument);
384 }
385
386 if self.oracle_public_key != announcement.oracle_public_key {
387 return Err(Error::InvalidArgument);
388 }
389
390 self.signatures
391 .iter()
392 .zip(self.outcomes.iter())
393 .try_for_each(|(sig, outcome)| {
394 let msg = tagged_attestation_msg(outcome);
395 secp.verify_schnorr(sig, &msg, &self.oracle_public_key)
396 .map_err(|_| Error::InvalidArgument)?;
397
398 Ok::<(), ddk_dlc::Error>(())
399 })?;
400
401 if !self
402 .signatures
403 .iter()
404 .zip(announcement.oracle_event.oracle_nonces.iter())
405 .all(|(sig, nonce)| sig.encode()[..32] == nonce.serialize())
406 {
407 return Err(Error::InvalidArgument);
408 }
409
410 Ok(())
411 }
412 pub fn nonces(&self) -> Vec<XOnlyPublicKey> {
415 self.signatures
416 .iter()
417 .map(|s| XOnlyPublicKey::from_slice(&s[0..32]).expect("valid signature"))
418 .collect()
419 }
420}
421
422impl Type for OracleAttestation {
423 fn type_id(&self) -> u16 {
424 ATTESTATION_TYPE
425 }
426}
427
428impl_dlc_writeable!(OracleAttestation, {
429 (event_id, string),
430 (oracle_public_key, {cb_writeable, write_schnorr_pubkey, read_schnorr_pubkey}),
431 (signatures, {vec_u16_cb, write_schnorrsig, read_schnorrsig}),
432 (outcomes, {cb_writeable, write_strings_u16, read_strings_u16})
433});
434
435#[cfg(test)]
436mod tests {
437 use super::*;
438 use bitcoin::bip32::{ChildNumber, Xpriv};
439 use bitcoin::Network;
440 use secp256k1_zkp::rand::Fill;
441 use secp256k1_zkp::SecretKey;
442 use secp256k1_zkp::{rand::thread_rng, SECP256K1};
443 use secp256k1_zkp::{schnorr::Signature as SchnorrSignature, Keypair, XOnlyPublicKey};
444
445 fn enum_descriptor() -> EnumEventDescriptor {
446 EnumEventDescriptor {
447 outcomes: vec!["1".to_string(), "2".to_string(), "3".to_string()],
448 }
449 }
450
451 fn digit_descriptor() -> DigitDecompositionEventDescriptor {
452 DigitDecompositionEventDescriptor {
453 base: 2,
454 is_signed: false,
455 unit: "kg/sats".to_string(),
456 precision: 1,
457 nb_digits: 10,
458 }
459 }
460
461 fn signed_digit_descriptor() -> DigitDecompositionEventDescriptor {
462 DigitDecompositionEventDescriptor {
463 base: 2,
464 is_signed: true,
465 unit: "kg/sats".to_string(),
466 precision: 1,
467 nb_digits: 10,
468 }
469 }
470
471 fn some_schnorr_pubkey() -> XOnlyPublicKey {
472 let key_pair = Keypair::new(SECP256K1, &mut thread_rng());
473 XOnlyPublicKey::from_keypair(&key_pair).0
474 }
475
476 fn digit_event(nb_nonces: usize) -> OracleEvent {
477 OracleEvent {
478 oracle_nonces: (0..nb_nonces).map(|_| some_schnorr_pubkey()).collect(),
479 event_maturity_epoch: 10,
480 event_descriptor: EventDescriptor::DigitDecompositionEvent(digit_descriptor()),
481 event_id: "test".to_string(),
482 }
483 }
484
485 fn signed_digit_event(nb_nonces: usize) -> OracleEvent {
486 OracleEvent {
487 oracle_nonces: (0..nb_nonces).map(|_| some_schnorr_pubkey()).collect(),
488 event_maturity_epoch: 10,
489 event_descriptor: EventDescriptor::DigitDecompositionEvent(signed_digit_descriptor()),
490 event_id: "test-signed".to_string(),
491 }
492 }
493
494 fn enum_event(nb_nonces: usize) -> OracleEvent {
495 OracleEvent {
496 oracle_nonces: (0..nb_nonces).map(|_| some_schnorr_pubkey()).collect(),
497 event_maturity_epoch: 10,
498 event_descriptor: EventDescriptor::EnumEvent(enum_descriptor()),
499 event_id: "test".to_string(),
500 }
501 }
502
503 fn create_nonce_key() -> (SecretKey, XOnlyPublicKey) {
504 let mut nonce_seed = [0u8; 32];
505 nonce_seed.try_fill(&mut thread_rng()).unwrap();
506 let nonce_priv = Xpriv::new_master(Network::Bitcoin, &nonce_seed)
507 .unwrap()
508 .derive_priv(SECP256K1, &[ChildNumber::from_normal_idx(1).unwrap()])
509 .unwrap()
510 .private_key;
511
512 let nonce_xpub = nonce_priv.x_only_public_key(SECP256K1).0;
513
514 (nonce_priv, nonce_xpub)
515 }
516
517 #[test]
518 fn valid_oracle_announcement_passes_validation_test() {
519 let key_pair = Keypair::new(SECP256K1, &mut thread_rng());
520 let oracle_pubkey = XOnlyPublicKey::from_keypair(&key_pair).0;
521 let events = [digit_event(10), signed_digit_event(11), enum_event(1)];
522 for event in events {
523 let msg = tagged_announcement_msg(&event);
524 let sig = SECP256K1.sign_schnorr(&msg, &key_pair);
525 let valid_announcement = OracleAnnouncement {
526 announcement_signature: sig,
527 oracle_public_key: oracle_pubkey,
528 oracle_event: event,
529 };
530
531 valid_announcement
532 .validate(SECP256K1)
533 .expect("a valid announcement.");
534 }
535 }
536
537 #[test]
538 fn invalid_oracle_announcement_fails_validation_test() {
539 let key_pair = Keypair::new(SECP256K1, &mut thread_rng());
540 let oracle_pubkey = XOnlyPublicKey::from_keypair(&key_pair).0;
541 let events = [digit_event(9), signed_digit_event(10), enum_event(2)];
542 for event in events {
543 let msg = tagged_announcement_msg(&event);
544 let sig = SECP256K1.sign_schnorr(&msg, &key_pair);
545 let invalid_announcement = OracleAnnouncement {
546 announcement_signature: sig,
547 oracle_public_key: oracle_pubkey,
548 oracle_event: event,
549 };
550
551 invalid_announcement
552 .validate(SECP256K1)
553 .expect_err("invalid announcement should fail validation.");
554 }
555 }
556
557 #[test]
558 fn invalid_oracle_announcement_signature_fails_validation_test() {
559 let key_pair = Keypair::new(SECP256K1, &mut thread_rng());
560 let oracle_pubkey = XOnlyPublicKey::from_keypair(&key_pair).0;
561 let event = digit_event(10);
562 let msg = tagged_announcement_msg(&event);
563 let sig = SECP256K1.sign_schnorr(&msg, &key_pair);
564 let mut sig_hex = *sig.as_ref();
565 sig_hex[10] = sig_hex[10].checked_add(1).unwrap_or(0);
566 let sig = SchnorrSignature::from_slice(&sig_hex).unwrap();
567 let invalid_announcement = OracleAnnouncement {
568 announcement_signature: sig,
569 oracle_public_key: oracle_pubkey,
570 oracle_event: event,
571 };
572
573 assert!(invalid_announcement.validate(SECP256K1).is_err());
574 }
575
576 #[test]
577 fn valid_oracle_attestation() {
578 let key_pair = Keypair::new(SECP256K1, &mut thread_rng());
579 let oracle_pubkey = XOnlyPublicKey::from_keypair(&key_pair).0;
580 let (nonce_secret, nonce_xpub) = create_nonce_key();
581
582 let oracle_event = OracleEvent {
583 event_id: "test".to_string(),
584 event_maturity_epoch: 10,
585 oracle_nonces: vec![nonce_xpub],
586 event_descriptor: EventDescriptor::EnumEvent(enum_descriptor()),
587 };
588
589 let msg = tagged_announcement_msg(&oracle_event);
590 let sig = SECP256K1.sign_schnorr(&msg, &key_pair);
591
592 let valid_announcement = OracleAnnouncement {
593 oracle_public_key: oracle_pubkey,
594 announcement_signature: sig,
595 oracle_event,
596 };
597
598 let msg = tagged_attestation_msg("1");
599 let sig = ddk_dlc::secp_utils::schnorrsig_sign_with_nonce(
600 SECP256K1,
601 &msg,
602 &key_pair,
603 &nonce_secret.secret_bytes(),
604 );
605
606 let attestation = OracleAttestation {
607 event_id: "test".to_string(),
608 oracle_public_key: oracle_pubkey,
609 signatures: vec![sig],
610 outcomes: vec!["1".to_string()],
611 };
612
613 let validation = attestation.validate(SECP256K1, &valid_announcement);
614
615 assert!(validation.is_ok())
616 }
617
618 #[test]
619 fn invalid_attestation_incorrect_nonce() {
620 let key_pair = Keypair::new(SECP256K1, &mut thread_rng());
621 let oracle_pubkey = XOnlyPublicKey::from_keypair(&key_pair).0;
622 let (_, nonce_xpub) = create_nonce_key();
623 let (incorrect_nonce_secret, _) = create_nonce_key();
624
625 let oracle_event = OracleEvent {
626 event_id: "test".to_string(),
627 event_maturity_epoch: 10,
628 oracle_nonces: vec![nonce_xpub],
629 event_descriptor: EventDescriptor::EnumEvent(enum_descriptor()),
630 };
631
632 let msg = tagged_announcement_msg(&oracle_event);
633 let sig = SECP256K1.sign_schnorr(&msg, &key_pair);
634
635 let valid_announcement = OracleAnnouncement {
636 oracle_public_key: oracle_pubkey,
637 announcement_signature: sig,
638 oracle_event,
639 };
640
641 let msg = tagged_attestation_msg("1");
642 let sig = ddk_dlc::secp_utils::schnorrsig_sign_with_nonce(
643 SECP256K1,
644 &msg,
645 &key_pair,
646 &incorrect_nonce_secret.secret_bytes(),
647 );
648
649 let attestation = OracleAttestation {
650 event_id: "test".to_string(),
651 oracle_public_key: oracle_pubkey,
652 signatures: vec![sig],
653 outcomes: vec!["1".to_string()],
654 };
655
656 let validation = attestation.validate(SECP256K1, &valid_announcement);
657
658 assert!(validation.is_err())
659 }
660}