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