diff --git a/Cargo.lock b/Cargo.lock index 761d4752..fbb9e438 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,9 +25,9 @@ dependencies = [ [[package]] name = "amplify" -version = "4.7.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7147b742325842988dd6c793d55f58df3ae36bccf7d9b6e07db10ab035be343d" +checksum = "b2090b9b79b61d4047a307a46de043d0ee5ec406d99a7d652341b96d48ed5567" dependencies = [ "amplify_apfloat", "amplify_derive", @@ -172,12 +172,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" -[[package]] -name = "bitcoin-private" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" - [[package]] name = "bitcoin_hashes" version = "0.14.0" @@ -218,14 +212,14 @@ dependencies = [ [[package]] name = "bp-consensus" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54db63118d55e32ea78f8775e98871d442a33e3bdef6419c7964d71b308316c0" +checksum = "40f227ce25d185bc5fc9109ca83dfa8bd0e745f219e320f3da658aaf4fd7e0c5" dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1 0.30.0", + "secp256k1", "serde", "strict_encoding", "strict_types", @@ -233,9 +227,9 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e51a329150531b12243adf51d978490c796a6a20ec76c506b41c8e1226022bc" +checksum = "40c6b213ada98fe5e78a978e67a7044d16d2571edb3f85fcdb4246324ec9514a" dependencies = [ "amplify", "bp-consensus", @@ -252,24 +246,24 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9286fb448160672148262317f4647ebdcdd4699ed2bd34401f9799d0920cc376" +checksum = "d33d4cc345a595236441fc2b8726ca7eb693947914b278849d1e2c1923dcb314" dependencies = [ "amplify", "base85", "bp-consensus", "commit_verify", - "secp256k1 0.30.0", + "secp256k1", "serde", "strict_encoding", ] [[package]] name = "bp-seals" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9873cfe420f4ce5cc539c394c75df0669cdbe2c23eed1930dffe024cb0f13a57" +checksum = "6a7a009fbf7e71be7ab5f43e032c69927f58cd7f59a6a822af64f84d3e8d41c5" dependencies = [ "amplify", "baid64", @@ -325,9 +319,9 @@ dependencies = [ [[package]] name = "commit_encoding_derive" -version = "0.11.0-beta.8" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea07c5ad73a637276dc4f8a957f8285764018d45bdefef35eb9137f32d0e3c81" +checksum = "dc09678c15e9280cc6eaf29bf437a2cf18fadedd8bf78c369b8ac15fa217dbe5" dependencies = [ "amplify", "amplify_syn", @@ -338,9 +332,9 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0-beta.9" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf08c4941e147937551f6a3d370552d67f98cf72c9eb18948142596beadd31e" +checksum = "0fcf5f557e112c684f2458f20c66bab865c01cab56d6a318f64243cba9b163a7" dependencies = [ "amplify", "commit_encoding_derive", @@ -650,7 +644,7 @@ dependencies = [ "getrandom", "mime", "rand", - "secp256k1-zkp", + "secp256k1", "serde", "single_use_seals", "strict_encoding", @@ -689,17 +683,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" -[[package]] -name = "secp256k1" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" -dependencies = [ - "rand", - "secp256k1-sys", - "serde", -] - [[package]] name = "secp256k1" version = "0.30.0" @@ -721,29 +704,6 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-zkp" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" -dependencies = [ - "bitcoin-private", - "rand", - "secp256k1 0.29.1", - "secp256k1-zkp-sys", - "serde", -] - -[[package]] -name = "secp256k1-zkp-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f08b2d0b143a22e07f798ae4f0ab20d5590d7c68e0d090f2088a48a21d1654" -dependencies = [ - "cc", - "secp256k1-sys", -] - [[package]] name = "serde" version = "1.0.214" @@ -827,9 +787,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0-beta.9" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec071f3b3153217f1cb2bca5ba7ac87eeafc446cb35a5c0643dec33495a37244" +checksum = "b01aad2d785dc858c4f652d1e18d0c815cd10aa8f15ac7accd2b12b894d7c367" dependencies = [ "amplify_derive", ] diff --git a/Cargo.toml b/Cargo.toml index a87ec3bf..c4a4608e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,8 +29,8 @@ strict_types = { version = "~2.7.2", features = ["armor"] } aluvm = { version = "~0.11.0-beta.9", features = ["std", "ascii-armor"] } commit_verify = { version = "~0.11.0-beta.9", features = ["rand", "derive"] } single_use_seals = "~0.11.0-beta.9" -bp-core = { version = "~0.11.0-beta.9" } -secp256k1-zkp = { version = "0.11.0", features = ["rand", "rand-std", "global-context"] } # TODO: Update version before the release +bp-core = { version = "~0.11.1-alpha.1" } +secp256k1 = { version = "0.30.0", features = ["global-context"] } mime = "~0.3.17" serde_crate = { package = "serde", version = "1", features = ["derive"], optional = true } chrono = "0.4.38" @@ -47,7 +47,7 @@ serde = [ "commit_verify/serde", "bp-core/serde", "aluvm/serde", - "secp256k1-zkp/serde" + "secp256k1/serde" ] [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/doc/Commitments.md b/doc/Commitments.md index 9eb90d18..f4cc84cf 100644 --- a/doc/Commitments.md +++ b/doc/Commitments.md @@ -201,10 +201,9 @@ assignments are concealed before the merklization, and range proofs are removed from the commitment, such that an aggregation of the historical proofs can be applied without changing the operation ids. -To ensure succinctness, other types of collections, such as redeemed and -defined valencies and list of alternate layer 1 in genesis are not merklized -and strict-serialized producing `StrictHash`, which participates in the final -`OpCommitment` structure. +To ensure succinctness, other types of collections, such as redeemed and +defined valencies in genesis are not merklized and strict-serialized producing +`StrictHash`, which participates in the final `OpCommitment` structure. ```mermaid flowchart LR @@ -221,8 +220,7 @@ flowchart LR subgraph "Genesis" schemaId --> BaseCommitment - testnet --> BaseCommitment - altLayers1 -- StrictHash --> BaseCommitment + chainNet --> BaseCommitment end subgraph "Transition" diff --git a/src/lib.rs b/src/lib.rs index 22194544..4ca1c337 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,10 +44,10 @@ pub mod vm; pub mod stl; pub mod prelude { + pub use bp::Txid; pub use commit_verify::ReservedBytes; pub use operation::*; pub use schema::*; - pub use vm::XWitnessId; #[cfg(feature = "stl")] pub use super::stl; diff --git a/src/operation/assignments.rs b/src/operation/assignments.rs index 7e719423..65459a67 100644 --- a/src/operation/assignments.rs +++ b/src/operation/assignments.rs @@ -33,7 +33,7 @@ use super::ExposedState; use crate::operation::seal::GenesisSeal; use crate::{ AssignmentType, ExposedSeal, GraphSeal, RevealedAttach, RevealedData, RevealedValue, - SecretSeal, StateType, VoidState, XChain, LIB_NAME_RGB_COMMIT, + SecretSeal, StateType, VoidState, LIB_NAME_RGB_COMMIT, }; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Display, Error)] @@ -54,45 +54,26 @@ pub type AssignAttach<Seal> = Assign<RevealedAttach, Seal>; #[strict_type( lib = LIB_NAME_RGB_COMMIT, tags = custom, - dumb = { Self::Confidential { seal: strict_dumb!(), state: strict_dumb!(), lock: default!() } } + dumb = { Self::Revealed { seal: strict_dumb!(), state: strict_dumb!(), lock: default!() } } )] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), - serde( - crate = "serde_crate", - rename_all = "camelCase", - untagged, - bound = "State::Confidential: serde::Serialize + serde::de::DeserializeOwned, State: \ - serde::Serialize + serde::de::DeserializeOwned, Seal: serde::Serialize + \ - serde::de::DeserializeOwned" - ) + serde(crate = "serde_crate", rename_all = "camelCase", untagged) )] pub enum Assign<State: ExposedState, Seal: ExposedSeal> { #[strict_type(tag = 0x00)] - Confidential { - seal: XChain<SecretSeal>, - state: State::Confidential, - lock: ReservedBytes<2, 0>, - }, - #[strict_type(tag = 0x03)] Revealed { - seal: XChain<Seal>, + seal: Seal, state: State, lock: ReservedBytes<2, 0>, }, - #[strict_type(tag = 0x02)] + #[strict_type(tag = 0x01)] ConfidentialSeal { - seal: XChain<SecretSeal>, + seal: SecretSeal, state: State, lock: ReservedBytes<2, 0>, }, - #[strict_type(tag = 0x01)] - ConfidentialState { - seal: XChain<Seal>, - state: State::Confidential, - lock: ReservedBytes<2, 0>, - }, } // Consensus-critical! @@ -113,14 +94,14 @@ impl<State: ExposedState, Seal: ExposedSeal> Ord for Assign<State, Seal> { impl<State: ExposedState, Seal: ExposedSeal> PartialEq for Assign<State, Seal> { fn eq(&self, other: &Self) -> bool { self.to_confidential_seal() == other.to_confidential_seal() - && self.to_confidential_state() == other.to_confidential_state() + && self.as_revealed_state() == other.as_revealed_state() } } impl<State: ExposedState, Seal: ExposedSeal> Eq for Assign<State, Seal> {} impl<State: ExposedState, Seal: ExposedSeal> Assign<State, Seal> { - pub fn revealed(seal: XChain<Seal>, state: State) -> Self { + pub fn revealed(seal: Seal, state: State) -> Self { Assign::Revealed { seal, state, @@ -128,22 +109,8 @@ impl<State: ExposedState, Seal: ExposedSeal> Assign<State, Seal> { } } - pub fn with_seal_replaced(assignment: &Self, seal: XChain<Seal>) -> Self { + pub fn with_seal_replaced(assignment: &Self, seal: Seal) -> Self { match assignment { - Assign::Confidential { - seal: _, - state, - lock, - } - | Assign::ConfidentialState { - seal: _, - state, - lock, - } => Assign::ConfidentialState { - seal, - state: *state, - lock: *lock, - }, Assign::ConfidentialSeal { seal: _, state, @@ -161,67 +128,53 @@ impl<State: ExposedState, Seal: ExposedSeal> Assign<State, Seal> { } } - pub fn to_confidential_seal(&self) -> XChain<SecretSeal> { - match self { - Assign::Revealed { seal, .. } | Assign::ConfidentialState { seal, .. } => { - seal.conceal() - } - Assign::Confidential { seal, .. } | Assign::ConfidentialSeal { seal, .. } => *seal, - } - } - - pub fn revealed_seal(&self) -> Option<XChain<Seal>> { + pub fn to_confidential_seal(&self) -> SecretSeal { match self { - Assign::Revealed { seal, .. } | Assign::ConfidentialState { seal, .. } => Some(*seal), - Assign::Confidential { .. } | Assign::ConfidentialSeal { .. } => None, + Assign::Revealed { seal, .. } => seal.conceal(), + Assign::ConfidentialSeal { seal, .. } => *seal, } } - pub fn to_confidential_state(&self) -> State::Confidential { + pub fn revealed_seal(&self) -> Option<Seal> { match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => { - state.conceal() - } - Assign::Confidential { state, .. } | Assign::ConfidentialState { state, .. } => *state, + Assign::Revealed { seal, .. } => Some(*seal), + Assign::ConfidentialSeal { .. } => None, } } - pub fn as_revealed_state(&self) -> Option<&State> { + pub fn as_revealed_state(&self) -> &State { match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => Some(state), - Assign::Confidential { .. } | Assign::ConfidentialState { .. } => None, + Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => state, } } - pub fn as_revealed_state_mut(&mut self) -> Option<&mut State> { + pub fn as_revealed_state_mut(&mut self) -> &mut State { match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => Some(state), - Assign::Confidential { .. } | Assign::ConfidentialState { .. } => None, + Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => state, } } - pub fn into_revealed_state(self) -> Option<State> { + pub fn into_revealed_state(self) -> State { match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => Some(state), - Assign::Confidential { .. } | Assign::ConfidentialState { .. } => None, + Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => state, } } - pub fn as_revealed(&self) -> Option<(&XChain<Seal>, &State)> { + pub fn as_revealed(&self) -> Option<(&Seal, &State)> { match self { Assign::Revealed { seal, state, .. } => Some((seal, state)), _ => None, } } - pub fn to_revealed(&self) -> Option<(XChain<Seal>, State)> { + pub fn to_revealed(&self) -> Option<(Seal, State)> { match self { Assign::Revealed { seal, state, .. } => Some((*seal, state.clone())), _ => None, } } - pub fn into_revealed(self) -> Option<(XChain<Seal>, State)> { + pub fn into_revealed(self) -> Option<(Seal, State)> { match self { Assign::Revealed { seal, state, .. } => Some((seal, state)), _ => None, @@ -236,22 +189,12 @@ where Self: Clone fn conceal(&self) -> Self::Concealed { match self { - Assign::Confidential { .. } => self.clone(), - Assign::ConfidentialState { seal, state, lock } => Self::Confidential { - seal: seal.conceal(), - state: *state, - lock: *lock, - }, - Assign::Revealed { seal, state, lock } => Self::Confidential { + Assign::Revealed { seal, state, lock } => Self::ConfidentialSeal { seal: seal.conceal(), - state: state.conceal(), - lock: *lock, - }, - Assign::ConfidentialSeal { seal, state, lock } => Self::Confidential { - seal: *seal, - state: state.conceal(), + state: state.clone(), lock: *lock, }, + Assign::ConfidentialSeal { .. } => self.clone(), } } } @@ -259,11 +202,6 @@ where Self: Clone impl<State: ExposedState> Assign<State, GenesisSeal> { pub fn transmutate_seals(&self) -> Assign<State, GraphSeal> { match self { - Assign::Confidential { seal, state, lock } => Assign::Confidential { - seal: *seal, - state: *state, - lock: *lock, - }, Assign::ConfidentialSeal { seal, state, lock } => Assign::ConfidentialSeal { seal: *seal, state: state.clone(), @@ -274,11 +212,6 @@ impl<State: ExposedState> Assign<State, GenesisSeal> { state: state.clone(), lock: *lock, }, - Assign::ConfidentialState { seal, state, lock } => Assign::ConfidentialState { - seal: seal.transmutate(), - state: *state, - lock: *lock, - }, } } } @@ -445,7 +378,7 @@ impl<Seal: ExposedSeal> TypedAssigns<Seal> { /// If seal definition does not exist, returns [`UnknownDataError`]. If the /// seal is confidential, returns `Ok(None)`; otherwise returns revealed /// seal data packed as `Ok(Some(`[`Seal`]`))` - pub fn revealed_seal_at(&self, index: u16) -> Result<Option<XChain<Seal>>, UnknownDataError> { + pub fn revealed_seal_at(&self, index: u16) -> Result<Option<Seal>, UnknownDataError> { Ok(match self { TypedAssigns::Declarative(vec) => vec .get(index as usize) @@ -466,7 +399,7 @@ impl<Seal: ExposedSeal> TypedAssigns<Seal> { }) } - pub fn to_confidential_seals(&self) -> Vec<XChain<SecretSeal>> { + pub fn to_confidential_seals(&self) -> Vec<SecretSeal> { match self { TypedAssigns::Declarative(s) => s .iter() @@ -487,10 +420,7 @@ impl<Seal: ExposedSeal> TypedAssigns<Seal> { } } - pub fn as_structured_state_at( - &self, - index: u16, - ) -> Result<Option<&RevealedData>, UnknownDataError> { + pub fn as_structured_state_at(&self, index: u16) -> Result<&RevealedData, UnknownDataError> { match self { TypedAssigns::Structured(vec) => Ok(vec .get(index as usize) @@ -500,10 +430,7 @@ impl<Seal: ExposedSeal> TypedAssigns<Seal> { } } - pub fn as_fungible_state_at( - &self, - index: u16, - ) -> Result<Option<&RevealedValue>, UnknownDataError> { + pub fn as_fungible_state_at(&self, index: u16) -> Result<&RevealedValue, UnknownDataError> { match self { TypedAssigns::Fungible(vec) => Ok(vec .get(index as usize) @@ -513,10 +440,7 @@ impl<Seal: ExposedSeal> TypedAssigns<Seal> { } } - pub fn into_structured_state_at( - self, - index: u16, - ) -> Result<Option<RevealedData>, UnknownDataError> { + pub fn into_structured_state_at(self, index: u16) -> Result<RevealedData, UnknownDataError> { match self { TypedAssigns::Structured(vec) => { if index as usize >= vec.len() { @@ -528,10 +452,7 @@ impl<Seal: ExposedSeal> TypedAssigns<Seal> { } } - pub fn into_fungible_state_at( - self, - index: u16, - ) -> Result<Option<RevealedValue>, UnknownDataError> { + pub fn into_fungible_state_at(self, index: u16) -> Result<RevealedValue, UnknownDataError> { match self { TypedAssigns::Fungible(vec) => { if index as usize >= vec.len() { diff --git a/src/operation/attachment.rs b/src/operation/attachment.rs index 43084a06..2d53e1b7 100644 --- a/src/operation/attachment.rs +++ b/src/operation/attachment.rs @@ -27,13 +27,10 @@ use std::str::FromStr; use amplify::{ByteArray, Bytes32}; use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; use bp::secp256k1::rand::{random, Rng, RngCore}; -use commit_verify::{CommitId, CommitmentId, Conceal, DigestExt, Sha256}; use strict_encoding::{StrictEncode, StrictSerialize}; -use super::{ConfidentialState, ExposedState}; -use crate::{ - impl_serde_baid64, ConcealedState, MediaType, RevealedState, StateType, LIB_NAME_RGB_COMMIT, -}; +use super::ExposedState; +use crate::{impl_serde_baid64, MediaType, RevealedState, StateType, LIB_NAME_RGB_COMMIT}; /// Unique data attachment identifier #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] @@ -94,8 +91,6 @@ impl From<RevealedAttach> for AttachState { #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = ConcealedAttach)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -136,48 +131,10 @@ impl RevealedAttach { } impl ExposedState for RevealedAttach { - type Confidential = ConcealedAttach; fn state_type(&self) -> StateType { StateType::Attachment } fn state_data(&self) -> RevealedState { RevealedState::Attachment(self.clone()) } } -impl Conceal for RevealedAttach { - type Concealed = ConcealedAttach; - - fn conceal(&self) -> Self::Concealed { self.commit_id() } -} - -/// Confidential version of an attachment information. -/// -/// See also revealed version [`RevealedAttach`]. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct ConcealedAttach( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl ConfidentialState for ConcealedAttach { - fn state_type(&self) -> StateType { StateType::Attachment } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Attachment(*self) } -} - -impl From<Sha256> for ConcealedAttach { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for ConcealedAttach { - const TAG: &'static str = "urn:lnp-bp:rgb:state-attach#2024-02-12"; -} - #[cfg(test)] mod test { use super::*; diff --git a/src/operation/bundle.rs b/src/operation/bundle.rs index 6a69d4f1..46b25fc3 100644 --- a/src/operation/bundle.rs +++ b/src/operation/bundle.rs @@ -24,7 +24,6 @@ use std::collections::{btree_map, BTreeMap}; use amplify::confinement::{Confined, U16 as U16MAX}; use amplify::{Bytes32, Wrapper}; -use bp::seals::txout::CloseMethod; use bp::Vout; use commit_verify::{mpc, CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, Sha256}; use strict_encoding::{StrictDumb, StrictEncode}; @@ -109,7 +108,6 @@ impl<'a> IntoIterator for &'a InputMap { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct TransitionBundle { - pub close_method: CloseMethod, pub input_map: InputMap, pub known_transitions: Confined<BTreeMap<OpId, Transition>, 1, U16MAX>, } @@ -117,16 +115,12 @@ pub struct TransitionBundle { impl CommitEncode for TransitionBundle { type CommitmentId = BundleId; - fn commit_encode(&self, e: &mut CommitEngine) { - e.commit_to_serialized(&self.close_method); - e.commit_to_serialized(&self.input_map); - } + fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(&self.input_map); } } impl StrictDumb for TransitionBundle { fn strict_dumb() -> Self { Self { - close_method: strict_dumb!(), input_map: strict_dumb!(), known_transitions: Confined::with_key_value(strict_dumb!(), strict_dumb!()), } diff --git a/src/operation/commit.rs b/src/operation/commit.rs index 93796a4d..437ab744 100644 --- a/src/operation/commit.rs +++ b/src/operation/commit.rs @@ -37,11 +37,11 @@ use commit_verify::{ use strict_encoding::StrictDumb; use crate::{ - impl_serde_baid64, Assign, AssignmentType, Assignments, BundleId, ConcealedAttach, - ConcealedData, ConcealedState, ConfidentialState, DataState, ExposedSeal, ExposedState, - Extension, ExtensionType, Ffv, Genesis, GlobalState, GlobalStateType, Operation, - PedersenCommitment, Redeemed, SchemaId, SecretSeal, Transition, TransitionBundle, - TransitionType, TypedAssigns, XChain, LIB_NAME_RGB_COMMIT, + impl_serde_baid64, Assign, AssignmentType, Assignments, BundleId, ChainNet, DataState, + ExposedSeal, ExposedState, Extension, ExtensionType, Ffv, Genesis, GlobalState, + GlobalStateType, Operation, Redeemed, RevealedAttach, RevealedData, RevealedState, + RevealedValue, SchemaId, SecretSeal, Transition, TransitionBundle, TransitionType, + TypedAssigns, LIB_NAME_RGB_COMMIT, }; /// Unique contract identifier equivalent to the contract genesis commitment @@ -188,10 +188,10 @@ impl AssignmentIndex { #[commit_encode(strategy = strict, id = DiscloseHash)] pub struct OpDisclose { pub id: OpId, - pub seals: MediumOrdMap<AssignmentIndex, XChain<SecretSeal>>, - pub fungible: MediumOrdMap<AssignmentIndex, PedersenCommitment>, - pub data: MediumOrdMap<AssignmentIndex, ConcealedData>, - pub attach: MediumOrdMap<AssignmentIndex, ConcealedAttach>, + pub seals: MediumOrdMap<AssignmentIndex, SecretSeal>, + pub fungible: MediumOrdMap<AssignmentIndex, RevealedValue>, + pub data: MediumOrdMap<AssignmentIndex, RevealedData>, + pub attach: MediumOrdMap<AssignmentIndex, RevealedAttach>, } #[derive(Clone, Eq, PartialEq, Hash, Debug)] @@ -236,9 +236,7 @@ pub struct BaseCommitment { pub schema_id: SchemaId, pub timestamp: i64, pub issuer: StrictHash, - pub testnet: bool, - pub alt_layers1: StrictHash, - pub asset_tags: StrictHash, + pub chain_net: ChainNet, } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] @@ -280,10 +278,8 @@ impl Genesis { flags: self.flags, schema_id: self.schema_id, timestamp: self.timestamp, - testnet: self.testnet, - alt_layers1: self.alt_layers1.commit_id(), + chain_net: self.chain_net, issuer: self.issuer.commit_id(), - asset_tags: self.asset_tags.commit_id(), }; OpCommitment { ffv: self.ffv, @@ -339,22 +335,22 @@ impl Extension { } } -impl ConcealedState { +impl RevealedState { fn commit_encode(&self, e: &mut CommitEngine) { match self { - ConcealedState::Void => {} - ConcealedState::Fungible(val) => e.commit_to_serialized(&val.commitment), - ConcealedState::Structured(dat) => e.commit_to_serialized(dat), - ConcealedState::Attachment(att) => e.commit_to_serialized(att), + Self::Void => {} + Self::Fungible(val) => e.commit_to_serialized(&val), + Self::Structured(dat) => e.commit_to_serialized(dat), + Self::Attachment(att) => e.commit_to_serialized(att), } } } -#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, Debug)] pub struct AssignmentCommitment { pub ty: AssignmentType, - pub state: ConcealedState, - pub seal: XChain<SecretSeal>, + pub state: RevealedState, + pub seal: SecretSeal, pub lock: ReservedBytes<2, 0>, } @@ -372,12 +368,12 @@ impl CommitEncode for AssignmentCommitment { impl<State: ExposedState, Seal: ExposedSeal> Assign<State, Seal> { pub fn commitment(&self, ty: AssignmentType) -> AssignmentCommitment { - let Self::Confidential { seal, state, lock } = self.conceal() else { + let Self::ConfidentialSeal { seal, state, lock } = self.conceal() else { unreachable!(); }; AssignmentCommitment { ty, - state: state.state_commitment(), + state: state.state_data(), seal, lock, } diff --git a/src/operation/data.rs b/src/operation/data.rs index 1ad420b0..b841da22 100644 --- a/src/operation/data.rs +++ b/src/operation/data.rs @@ -25,13 +25,12 @@ use std::cmp::Ordering; use amplify::confinement::SmallBlob; use amplify::hex::ToHex; -use amplify::{Bytes32, Wrapper}; +use amplify::Wrapper; use bp::secp256k1::rand::{random, Rng, RngCore}; -use commit_verify::{CommitId, CommitmentId, Conceal, DigestExt, Sha256}; use strict_encoding::{StrictSerialize, StrictType}; -use super::{ConfidentialState, ExposedState}; -use crate::{ConcealedState, RevealedState, StateType, LIB_NAME_RGB_COMMIT}; +use super::ExposedState; +use crate::{RevealedState, StateType, LIB_NAME_RGB_COMMIT}; /// Struct using for storing Void (i.e. absent) state #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Display, Default)] @@ -41,22 +40,11 @@ use crate::{ConcealedState, RevealedState, StateType, LIB_NAME_RGB_COMMIT}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct VoidState(()); -impl ConfidentialState for VoidState { - fn state_type(&self) -> StateType { StateType::Void } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Void } -} - impl ExposedState for VoidState { - type Confidential = VoidState; fn state_type(&self) -> StateType { StateType::Void } fn state_data(&self) -> RevealedState { RevealedState::Void } } -impl Conceal for VoidState { - type Concealed = VoidState; - fn conceal(&self) -> Self::Concealed { *self } -} - #[derive(Wrapper, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, From, Display, Default)] #[display(LowerHex)] #[wrapper(Deref, AsSlice, BorrowSlice, Hex)] @@ -96,8 +84,6 @@ mod _serde { #[derive(Clone, Eq, PartialEq, Hash)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = ConcealedData)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct RevealedData { pub value: DataState, @@ -125,17 +111,10 @@ impl RevealedData { } impl ExposedState for RevealedData { - type Confidential = ConcealedData; fn state_type(&self) -> StateType { StateType::Structured } fn state_data(&self) -> RevealedState { RevealedState::Structured(self.clone()) } } -impl Conceal for RevealedData { - type Concealed = ConcealedData; - - fn conceal(&self) -> Self::Concealed { self.commit_id() } -} - impl PartialOrd for RevealedData { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } @@ -159,34 +138,3 @@ impl Debug for RevealedData { .finish() } } - -/// Confidential version of an structured state data. -/// -/// See also revealed version [`RevealedData`]. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, rename = "ConcealedData")] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct ConcealedData( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl ConfidentialState for ConcealedData { - fn state_type(&self) -> StateType { StateType::Structured } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Structured(*self) } -} - -impl From<Sha256> for ConcealedData { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for ConcealedData { - const TAG: &'static str = "urn:lnp-bp:rgb:state-data#2024-02-12"; -} diff --git a/src/operation/fungible.rs b/src/operation/fungible.rs index 1af77801..9e82758c 100644 --- a/src/operation/fungible.rs +++ b/src/operation/fungible.rs @@ -30,76 +30,15 @@ //! properties regarding their total sum and, thus, can be made confidential //! using elliptic curve homomorphic cryptography such as Pedesen commitments. -use core::cmp::Ordering; use core::fmt::Debug; use core::num::ParseIntError; -use core::ops::Deref; use core::str::FromStr; use std::hash::Hash; -use std::io; -use amplify::confinement::U8; -use amplify::hex::ToHex; -// We do not import particular modules to keep aware with namespace prefixes -// that we do not use the standard secp256k1zkp library -use amplify::{hex, Array, Bytes32, Wrapper}; -use bp::secp256k1::rand::thread_rng; -use chrono::{DateTime, Utc}; -use commit_verify::{ - CommitVerify, CommitmentProtocol, Conceal, DigestExt, Sha256, UntaggedProtocol, -}; -use secp256k1_zkp::rand::{Rng, RngCore}; -use secp256k1_zkp::SECP256K1; -use strict_encoding::{ - DecodeError, ReadTuple, StrictDecode, StrictDumb, StrictEncode, TypedRead, TypedWrite, - WriteTuple, -}; +use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; -use super::{ConfidentialState, ExposedState}; -use crate::{ - schema, AssignmentType, ConcealedState, RevealedState, StateType, LIB_NAME_RGB_COMMIT, -}; - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AssetTag( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl AssetTag { - pub fn new_random(contract_domain: impl AsRef<str>, assignment_type: AssignmentType) -> Self { - AssetTag::new_deterministic( - contract_domain, - assignment_type, - Utc::now(), - thread_rng().next_u64(), - ) - } - - pub fn new_deterministic( - contract_domain: impl AsRef<str>, - assignment_type: AssignmentType, - timestamp: DateTime<Utc>, - salt: u64, - ) -> Self { - let timestamp = timestamp.timestamp(); - let mut hasher = Sha256::default(); - hasher.input_with_len::<U8>(contract_domain.as_ref().as_bytes()); - hasher.input_raw(&assignment_type.to_le_bytes()); - hasher.input_raw(×tamp.to_le_bytes()); - hasher.input_raw(&salt.to_le_bytes()); - AssetTag::from(hasher.finish()) - } -} +use super::ExposedState; +use crate::{schema, RevealedState, StateType, LIB_NAME_RGB_COMMIT}; /// An atom of an additive state, which thus can be monomorphically encrypted. #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)] @@ -150,487 +89,28 @@ impl FungibleState { pub fn as_u64(&self) -> u64 { (*self).into() } } -/// value provided for a blinding factor overflows prime field order for -/// Secp256k1 curve. -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error, From)] -#[display(doc_comments)] -#[from(secp256k1_zkp::UpstreamError)] -pub struct InvalidFieldElement; - -/// Errors parsing string representation of a blinding factor. -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum BlindingParseError { - /// invalid blinding factor hex representation - {0} - #[from] - Hex(hex::Error), - - /// blinding factor value is invalid and does not belong to the Secp256k1 - /// curve field. - #[from(InvalidFieldElement)] - InvalidFieldElement, -} - -/// Blinding factor used in creating Pedersen commitment to an [`AtomicValue`]. -/// -/// Knowledge of the blinding factor is important to reproduce the commitment -/// process if the original value is kept. -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[display(Self::to_hex)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", try_from = "secp256k1_zkp::SecretKey") -)] -pub struct BlindingFactor(Bytes32); - -impl BlindingFactor { - pub const EMPTY: Self = BlindingFactor(Bytes32::from_array([0x7E; 32])); -} - -impl Deref for BlindingFactor { - type Target = [u8; 32]; - fn deref(&self) -> &Self::Target { self.0.as_inner() } -} - -impl ToHex for BlindingFactor { - fn to_hex(&self) -> String { self.0.to_hex() } -} - -impl FromStr for BlindingFactor { - type Err = BlindingParseError; - fn from_str(s: &str) -> Result<Self, Self::Err> { - let bytes = Bytes32::from_str(s)?; - Self::try_from(bytes).map_err(BlindingParseError::from) - } -} - -impl From<secp256k1_zkp::SecretKey> for BlindingFactor { - fn from(key: secp256k1_zkp::SecretKey) -> Self { Self(Bytes32::from_inner(*key.as_ref())) } -} - -impl From<BlindingFactor> for secp256k1_zkp::SecretKey { - fn from(bf: BlindingFactor) -> Self { bf.to_secret_key() } -} - -impl BlindingFactor { - /// Creates a random blinding factor. - #[inline] - pub fn random() -> Self { Self::random_custom(&mut thread_rng()) } - - /// Generates a random blinding factor using custom random number generator. - #[inline] - pub fn random_custom<R: Rng + RngCore>(rng: &mut R) -> Self { - secp256k1_zkp::SecretKey::new(rng).into() - } - - /// Generates new blinding factor which balances a given set of negatives - /// and positives into zero. - /// - /// # Errors - /// - /// * if negatives are empty set; - /// * if any subset of the negatives or positives are inverses of other negatives or positives, - /// * if the balancing factor is zero (sum of negatives already equal to the sum of positives). - pub fn zero_balanced( - negative: impl IntoIterator<Item = BlindingFactor>, - positive: impl IntoIterator<Item = BlindingFactor>, - ) -> Result<Self, InvalidFieldElement> { - let mut blinding_neg_sum = secp256k1_zkp::Scalar::ZERO; - let mut blinding_pos_sum = secp256k1_zkp::Scalar::ZERO; - for neg in negative { - blinding_neg_sum = neg.to_secret_key().add_tweak(&blinding_neg_sum)?.into(); - } - let blinding_neg_sum = - secp256k1_zkp::SecretKey::from_slice(&blinding_neg_sum.to_be_bytes())?.negate(); - for pos in positive { - blinding_pos_sum = pos.to_secret_key().add_tweak(&blinding_pos_sum)?.into(); - } - let blinding_correction = blinding_neg_sum.add_tweak(&blinding_pos_sum)?.negate(); - Ok(blinding_correction.into()) - } - - fn to_secret_key(self) -> secp256k1_zkp::SecretKey { - secp256k1_zkp::SecretKey::from_slice(self.0.as_slice()) - .expect("blinding factor is an invalid secret key") - } -} - -impl TryFrom<[u8; 32]> for BlindingFactor { - type Error = InvalidFieldElement; - - fn try_from(array: [u8; 32]) -> Result<Self, Self::Error> { - secp256k1_zkp::SecretKey::from_slice(&array) - .map_err(|_| InvalidFieldElement) - .map(Self::from) - } -} - -impl TryFrom<Bytes32> for BlindingFactor { - type Error = InvalidFieldElement; - - fn try_from(bytes: Bytes32) -> Result<Self, Self::Error> { - Self::try_from(bytes.to_byte_array()) - } -} - /// State item for a homomorphically-encryptable state. /// /// Consists of the 64-bit value and -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_COMMIT, rename = "RevealedFungible")] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct RevealedValue { /// Original value in smallest indivisible units pub value: FungibleState, - - /// Blinding factor used in Pedersen commitment - pub blinding: BlindingFactor, - - /// Asset-specific tag preventing mixing assets of different type. - pub tag: AssetTag, } impl RevealedValue { - /// Constructs new state using the provided value using random blinding - /// factor. - pub fn new_random_blinding(value: impl Into<FungibleState>, tag: AssetTag) -> Self { - Self::with_blinding(value, BlindingFactor::random(), tag) - } - - /// Constructs new state using the provided value and random generator for - /// creating blinding factor. - pub fn with_rng<R: Rng + RngCore>( - value: impl Into<FungibleState>, - rng: &mut R, - tag: AssetTag, - ) -> Self { - Self::with_blinding(value, BlindingFactor::random_custom(rng), tag) - } - /// Convenience constructor. - pub fn with_blinding( - value: impl Into<FungibleState>, - blinding: BlindingFactor, - tag: AssetTag, - ) -> Self { + pub fn new(value: impl Into<FungibleState>) -> Self { Self { value: value.into(), - blinding, - tag, } } } impl ExposedState for RevealedValue { - type Confidential = ConcealedValue; fn state_type(&self) -> StateType { StateType::Fungible } fn state_data(&self) -> RevealedState { RevealedState::Fungible(*self) } } - -impl Conceal for RevealedValue { - type Concealed = ConcealedValue; - - fn conceal(&self) -> Self::Concealed { ConcealedValue::commit(self) } -} - -impl PartialOrd for RevealedValue { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } -} - -impl Ord for RevealedValue { - fn cmp(&self, other: &Self) -> Ordering { - match self.value.cmp(&other.value) { - Ordering::Equal => self.blinding.0.cmp(&other.blinding.0), - other => other, - } - } -} - -/// Opaque type holding pedersen commitment for an [`FungibleState`]. -#[derive(Wrapper, Copy, Clone, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, FromStr, Display, LowerHex)] -#[derive(StrictType)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct PedersenCommitment(secp256k1_zkp::PedersenCommitment); - -impl StrictDumb for PedersenCommitment { - fn strict_dumb() -> Self { - secp256k1_zkp::PedersenCommitment::from_slice(&[0x08; 33]) - .expect("hardcoded pedersen commitment value") - .into() - } -} - -impl StrictEncode for PedersenCommitment { - fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> { - writer.write_tuple::<Self>(|w| Ok(w.write_field(&self.0.serialize())?.complete())) - } -} - -impl StrictDecode for PedersenCommitment { - fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> { - reader.read_tuple(|r| { - let commitment = r.read_field::<[u8; 33]>()?; - secp256k1_zkp::PedersenCommitment::from_slice(&commitment) - .map_err(|_| { - DecodeError::DataIntegrityError(s!("invalid pedersen commitment data")) - }) - .map(PedersenCommitment::from_inner) - }) - } -} - -impl CommitVerify<RevealedValue, UntaggedProtocol> for PedersenCommitment { - fn commit(revealed: &RevealedValue) -> Self { - use secp256k1_zkp::{Generator, Tag, Tweak}; - - let blinding = Tweak::from_inner(revealed.blinding.0.into_inner()) - .expect("type guarantees of BlindingFactor are broken"); - let FungibleState::Bits64(value) = revealed.value; - - let tag = Tag::from(revealed.tag.to_byte_array()); - let generator = Generator::new_unblinded(SECP256K1, tag); - - secp256k1_zkp::PedersenCommitment::new(SECP256K1, value, blinding, generator).into() - } -} - -/// A dumb placeholder for a future bulletproofs. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct NoiseDumb(Array<u8, 512>); - -impl Default for NoiseDumb { - fn default() -> Self { - let mut dumb = [0u8; 512]; - thread_rng().fill(&mut dumb); - NoiseDumb(dumb.into()) - } -} - -/// Range proof value. -/// -/// Range proofs must be used alongside [`PedersenCommitment`]s to ensure that -/// the value do not overflow on arithmetic operations with the commitments. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", untagged) -)] -pub enum RangeProof { - /// Value used when bulletproofs library is not available. - /// - /// Always fails validation if no source value is given. - #[strict_type(tag = 0xFF)] - Placeholder(NoiseDumb), -} - -impl Default for RangeProof { - fn default() -> Self { RangeProof::Placeholder(default!()) } -} - -impl StrictEncode for RangeProof { - fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> { - eprintln!("bulletproof dummies must never be stored"); - Ok(writer) - } -} - -impl StrictDecode for RangeProof { - fn strict_decode(_: &mut impl TypedRead) -> Result<Self, DecodeError> { - panic!("bulletproofs dummies must never be read") - } -} - -pub struct PedersenProtocol; - -impl CommitmentProtocol for PedersenProtocol {} - -/// Confidential version of the additive state. -/// -/// See also revealed version [`RevealedValue`]. -#[derive(Clone, Copy, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, rename = "ConcealedFungible")] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ConcealedValue { - /// Pedersen commitment to the original [`FungibleState`]. - pub commitment: PedersenCommitment, - /// Range proof for the [`FungibleState`] not exceeding type boundaries. - pub range_proof: RangeProof, -} - -impl PartialEq for ConcealedValue { - fn eq(&self, other: &Self) -> bool { self.commitment == other.commitment } -} - -impl ConfidentialState for ConcealedValue { - fn state_type(&self) -> StateType { StateType::Fungible } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Fungible(*self) } -} - -impl CommitVerify<RevealedValue, PedersenProtocol> for ConcealedValue { - fn commit(revealed: &RevealedValue) -> Self { - let commitment = PedersenCommitment::commit(revealed); - // TODO: Do actual conceal upon integration of bulletproofs library - let range_proof = RangeProof::default(); - ConcealedValue { - commitment, - range_proof, - } - } -} - -/// Errors verifying range proofs. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum RangeProofError { - /// invalid blinding factor {0}. - InvalidBlinding(BlindingFactor), - - /// bulletproofs verification is not implemented in RGB Core v0.10. Please - /// update your software and try again, or ask your software producer to use - /// latest RGB release. - BulletproofsAbsent, -} - -impl ConcealedValue { - /// Verifies validity of the range proof. - pub fn verify_range_proof(&self) -> Result<bool, RangeProofError> { - // We always fail here - Err(RangeProofError::BulletproofsAbsent) - } -} - -#[cfg(test)] -mod test { - use amplify::ByteArray; - - use super::*; - - #[test] - fn pedersen_blinding_mismatch() { - let mut r = thread_rng(); - let tag = AssetTag::from_byte_array([1u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_rng(15, &mut r, tag)).into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_rng(7, &mut r, tag)).into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_rng(13, &mut r, tag)).into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_rng(9, &mut r, tag)).into_inner(); - - assert!(!secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } - - #[test] - fn pedersen_blinding_same() { - let blinding = - BlindingFactor::from(secp256k1_zkp::SecretKey::from_slice(&[1u8; 32]).unwrap()); - let tag = AssetTag::from_byte_array([1u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag)) - .into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag)) - .into_inner(); - - assert!(secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } - - #[test] - fn pedersen_blinding_same_tag_differ() { - let blinding = - BlindingFactor::from(secp256k1_zkp::SecretKey::from_slice(&[1u8; 32]).unwrap()); - let tag = AssetTag::from_byte_array([1u8; 32]); - let tag2 = AssetTag::from_byte_array([2u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag2)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag)) - .into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag2)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag)) - .into_inner(); - - assert!(!secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } - - #[test] - fn pedersen_two_tags() { - let blinding = - BlindingFactor::from(secp256k1_zkp::SecretKey::from_slice(&[1u8; 32]).unwrap()); - let tag = AssetTag::from_byte_array([1u8; 32]); - let tag2 = AssetTag::from_byte_array([2u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag2)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag2)) - .into_inner(); - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(2, blinding, tag)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(4, blinding, tag)) - .into_inner(); - - let e = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag2)) - .into_inner(); - let f = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag2)) - .into_inner(); - let g = PedersenCommitment::commit(&RevealedValue::with_blinding(1, blinding, tag)) - .into_inner(); - let h = PedersenCommitment::commit(&RevealedValue::with_blinding(5, blinding, tag)) - .into_inner(); - - assert!(secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b, c, d], &[ - e, f, g, h - ])) - } - - #[test] - fn pedersen_blinding_balance() { - let blinding1 = BlindingFactor::random(); - let blinding2 = BlindingFactor::random(); - let blinding3 = BlindingFactor::random(); - let blinding4 = BlindingFactor::zero_balanced([blinding1, blinding2], [blinding3]).unwrap(); - let tag = AssetTag::from_byte_array([1u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding1, tag)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding2, tag)) - .into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding3, tag)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding4, tag)) - .into_inner(); - - assert!(secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } -} diff --git a/src/operation/layer1.rs b/src/operation/layer1.rs new file mode 100644 index 00000000..574ff1da --- /dev/null +++ b/src/operation/layer1.rs @@ -0,0 +1,143 @@ +// RGB Core Library: consensus layer for RGB smart contracts. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky <orlovsky@lnp-bp.org> +// +// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::str::FromStr; + +use bp::BlockHash; +use strict_encoding::{StrictDecode, StrictEncode, StrictType}; + +use crate::LIB_NAME_RGB_COMMIT; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] +#[display(lowercase)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +#[repr(u8)] +#[derive(Default)] +pub enum Layer1 { + #[default] + Bitcoin = 0, + Liquid = 1, +} + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[display(inner)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +#[repr(u8)] +#[derive(Default)] +pub enum ChainNet { + BitcoinMainnet = 0, + BitcoinTestnet3 = 1, + #[default] + BitcoinTestnet4 = 2, + BitcoinSignet = 3, + BitcoinRegtest = 4, + LiquidMainnet = 5, + LiquidTestnet = 6, +} + +impl ChainNet { + pub fn prefix(&self) -> &str { + match self { + ChainNet::BitcoinMainnet => "bc", + ChainNet::BitcoinTestnet3 => "tb3", + ChainNet::BitcoinTestnet4 => "tb4", + ChainNet::BitcoinRegtest => "bcrt", + ChainNet::BitcoinSignet => "sb", + ChainNet::LiquidMainnet => "lq", + ChainNet::LiquidTestnet => "tl", + } + } + + pub fn layer1(&self) -> Layer1 { + match self { + ChainNet::BitcoinMainnet + | ChainNet::BitcoinTestnet3 + | ChainNet::BitcoinTestnet4 + | ChainNet::BitcoinSignet + | ChainNet::BitcoinRegtest => Layer1::Bitcoin, + ChainNet::LiquidMainnet | ChainNet::LiquidTestnet => Layer1::Liquid, + } + } + + pub fn genesis_block_hash(&self) -> BlockHash { + BlockHash::from_str(match self { + ChainNet::BitcoinMainnet => { + "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" + } + ChainNet::BitcoinTestnet3 => { + "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" + } + ChainNet::BitcoinTestnet4 => { + "00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043" + } + ChainNet::BitcoinSignet => { + "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6" + } + ChainNet::BitcoinRegtest => { + "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" + } + ChainNet::LiquidMainnet => { + "4f4eac81e5f9f04f5d2a17b03e6726e6a1af69d9c3f00d820f1c82fcb6000000" + } + ChainNet::LiquidTestnet => { + "f9f21a7636b35c12f080ff73fc8bb16bb7c3ceafdc2eb1b673f0ea7a40c00000" + } + }) + .unwrap() + } +} + +#[derive(Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum ChainNetParseError { + /// invalid chain-network pair {0}. + Invalid(String), +} + +impl FromStr for ChainNet { + type Err = ChainNetParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s.to_lowercase() { + x if ChainNet::BitcoinMainnet.prefix() == x => Ok(ChainNet::BitcoinMainnet), + x if ChainNet::BitcoinRegtest.prefix() == x => Ok(ChainNet::BitcoinRegtest), + x if ChainNet::BitcoinSignet.prefix() == x => Ok(ChainNet::BitcoinSignet), + x if ChainNet::BitcoinTestnet3.prefix() == x => Ok(ChainNet::BitcoinTestnet3), + x if ChainNet::BitcoinTestnet4.prefix() == x => Ok(ChainNet::BitcoinTestnet4), + x if ChainNet::LiquidMainnet.prefix() == x => Ok(ChainNet::LiquidMainnet), + x if ChainNet::LiquidTestnet.prefix() == x => Ok(ChainNet::LiquidTestnet), + _ => Err(ChainNetParseError::Invalid(s.to_owned())), + } + } +} diff --git a/src/operation/mod.rs b/src/operation/mod.rs index c13450be..6db1613c 100644 --- a/src/operation/mod.rs +++ b/src/operation/mod.rs @@ -30,36 +30,27 @@ pub mod seal; pub mod assignments; mod operations; mod bundle; -mod xchain; +mod layer1; mod commit; pub use assignments::{ Assign, AssignAttach, AssignData, AssignFungible, AssignRights, Assignments, AssignmentsRef, TypedAssigns, }; -pub use attachment::{AttachId, AttachState, ConcealedAttach, RevealedAttach}; +pub use attachment::{AttachId, AttachState, RevealedAttach}; pub use bundle::{BundleId, InputMap, TransitionBundle, Vin}; pub use commit::{ AssignmentCommitment, AssignmentIndex, BaseCommitment, BundleDisclosure, ContractId, DiscloseHash, GlobalCommitment, OpCommitment, OpDisclose, OpId, TypeCommitment, }; -pub use data::{ConcealedData, DataState, RevealedData, VoidState}; -pub use fungible::{ - AssetTag, BlindingFactor, BlindingParseError, ConcealedValue, FungibleState, - InvalidFieldElement, NoiseDumb, PedersenCommitment, RangeProof, RangeProofError, RevealedValue, -}; +pub use data::{DataState, RevealedData, VoidState}; +pub use fungible::{FungibleState, RevealedValue}; pub use global::{GlobalState, GlobalValues}; +pub use layer1::{ChainNet, Layer1}; pub use meta::{MetaValue, Metadata, MetadataError}; pub use operations::{ - AssetTags, Extension, Genesis, Identity, Input, Inputs, Operation, Opout, OpoutParseError, - Redeemed, Transition, Valencies, -}; -pub use seal::{ - ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, XGenesisSeal, XGraphSeal, - XOutputSeal, -}; -pub use state::{ConcealedState, ConfidentialState, ExposedState, RevealedState, StateType}; -pub use xchain::{ - AltLayer1, AltLayer1Set, Impossible, Layer1, XChain, XChainParseError, XOutpoint, - XCHAIN_BITCOIN_PREFIX, XCHAIN_LIQUID_PREFIX, + Extension, Genesis, Identity, Input, Inputs, Operation, Opout, OpoutParseError, Redeemed, + Transition, Valencies, }; +pub use seal::{ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal}; +pub use state::{ExposedState, RevealedState, StateType}; diff --git a/src/operation/operations.rs b/src/operation/operations.rs index e4ed6cf2..74c9174b 100644 --- a/src/operation/operations.rs +++ b/src/operation/operations.rs @@ -37,10 +37,10 @@ use strict_encoding::{RString, StrictDeserialize, StrictEncode, StrictSerialize} use crate::schema::{self, ExtensionType, OpFullType, OpType, SchemaId, TransitionType}; use crate::{ - AltLayer1Set, AssetTag, Assign, AssignmentIndex, AssignmentType, Assignments, AssignmentsRef, - ConcealedAttach, ConcealedData, ConcealedValue, ContractId, DiscloseHash, ExposedState, Ffv, - GenesisSeal, GlobalState, GraphSeal, Metadata, OpDisclose, OpId, SecretSeal, TypedAssigns, - VoidState, XChain, LIB_NAME_RGB_COMMIT, + Assign, AssignmentIndex, AssignmentType, Assignments, AssignmentsRef, ChainNet, ContractId, + DiscloseHash, ExposedState, Ffv, GenesisSeal, GlobalState, GraphSeal, Metadata, OpDisclose, + OpId, RevealedAttach, RevealedData, RevealedValue, SecretSeal, TypedAssigns, VoidState, + LIB_NAME_RGB_COMMIT, }; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] @@ -95,20 +95,6 @@ impl FromStr for Opout { } } -#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AssetTags(TinyOrdMap<AssignmentType, AssetTag>); - #[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From)] #[wrapper(Deref)] #[wrapper_mut(DerefMut)] @@ -261,24 +247,25 @@ pub trait Operation { fn proc_seals<State: ExposedState>( ty: AssignmentType, a: &[Assign<State, GraphSeal>], - seals: &mut BTreeMap<AssignmentIndex, XChain<SecretSeal>>, - state: &mut BTreeMap<AssignmentIndex, State::Concealed>, + seals: &mut BTreeMap<AssignmentIndex, SecretSeal>, + state: &mut BTreeMap<AssignmentIndex, State>, ) { for (index, assignment) in a.iter().enumerate() { if let Some(seal) = assignment.revealed_seal() { seals.insert(AssignmentIndex::new(ty, index as u16), seal.to_secret_seal()); } - if let Some(revealed) = assignment.as_revealed_state() { - state.insert(AssignmentIndex::new(ty, index as u16), revealed.conceal()); - } + state.insert( + AssignmentIndex::new(ty, index as u16), + assignment.as_revealed_state().clone(), + ); } } - let mut seals: BTreeMap<AssignmentIndex, XChain<SecretSeal>> = bmap!(); + let mut seals: BTreeMap<AssignmentIndex, SecretSeal> = bmap!(); let mut void: BTreeMap<AssignmentIndex, VoidState> = bmap!(); - let mut fungible: BTreeMap<AssignmentIndex, ConcealedValue> = bmap!(); - let mut data: BTreeMap<AssignmentIndex, ConcealedData> = bmap!(); - let mut attach: BTreeMap<AssignmentIndex, ConcealedAttach> = bmap!(); + let mut fungible: BTreeMap<AssignmentIndex, RevealedValue> = bmap!(); + let mut data: BTreeMap<AssignmentIndex, RevealedData> = bmap!(); + let mut attach: BTreeMap<AssignmentIndex, RevealedAttach> = bmap!(); for (ty, assigns) in self.assignments().flat() { match assigns { TypedAssigns::Declarative(a) => { @@ -299,9 +286,7 @@ pub trait Operation { OpDisclose { id: self.id(), seals: Confined::from_checked(seals), - fungible: Confined::from_iter_checked( - fungible.into_iter().map(|(k, s)| (k, s.commitment)), - ), + fungible: Confined::from_iter_checked(fungible), data: Confined::from_checked(data), attach: Confined::from_checked(attach), } @@ -359,9 +344,7 @@ pub struct Genesis { pub flags: ReservedBytes<1, 0>, pub timestamp: i64, pub issuer: Identity, - pub testnet: bool, - pub alt_layers1: AltLayer1Set, - pub asset_tags: AssetTags, + pub chain_net: ChainNet, pub metadata: Metadata, pub globals: GlobalState, pub assignments: Assignments<GenesisSeal>, diff --git a/src/operation/seal.rs b/src/operation/seal.rs index 186af74c..7b39baba 100644 --- a/src/operation/seal.rs +++ b/src/operation/seal.rs @@ -23,25 +23,18 @@ use core::fmt::Debug; use std::hash::Hash; -use bp::dbc::Method; pub use bp::seals::txout::blind::{ChainBlindSeal, ParseError, SingleBlindSeal}; +use bp::seals::txout::ExplicitSeal; pub use bp::seals::txout::TxoSeal; -use bp::seals::txout::{BlindSeal, CloseMethod, ExplicitSeal, SealTxid}; pub use bp::seals::SecretSeal; -use bp::{Outpoint, Txid, Vout}; +use bp::Txid; use commit_verify::Conceal; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; -use crate::{XChain, XOutpoint}; +pub type GenesisSeal = SingleBlindSeal; +pub type GraphSeal = ChainBlindSeal; -pub type GenesisSeal = SingleBlindSeal<Method>; -pub type GraphSeal = ChainBlindSeal<Method>; - -pub type OutputSeal = ExplicitSeal<Txid, Method>; - -pub type XGenesisSeal = XChain<GenesisSeal>; -pub type XGraphSeal = XChain<GraphSeal>; -pub type XOutputSeal = XChain<OutputSeal>; +pub type OutputSeal = ExplicitSeal<Txid>; pub trait ExposedSeal: Debug @@ -55,55 +48,21 @@ pub trait ExposedSeal: + TxoSeal + Conceal<Concealed = SecretSeal> { -} - -impl ExposedSeal for GraphSeal {} - -impl ExposedSeal for GenesisSeal {} - -impl<Seal: TxoSeal> TxoSeal for XChain<Seal> { - fn method(&self) -> CloseMethod { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.method(), - XChain::Other(_) => unreachable!(), - } - } - - fn txid(&self) -> Option<Txid> { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.txid(), - XChain::Other(_) => unreachable!(), - } - } - - fn vout(&self) -> Vout { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.vout(), - XChain::Other(_) => unreachable!(), - } + #[inline] + fn to_output_seal(self) -> Option<OutputSeal> { + let outpoint = self.outpoint()?; + Some(ExplicitSeal::new(outpoint)) } - fn outpoint(&self) -> Option<Outpoint> { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.outpoint(), - XChain::Other(_) => unreachable!(), - } + fn to_output_seal_or_default(self, witness_id: Txid) -> OutputSeal { + self.to_output_seal() + .unwrap_or(ExplicitSeal::new(self.outpoint_or(witness_id))) } +} - fn txid_or(&self, default_txid: Txid) -> Txid { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.txid_or(default_txid), - XChain::Other(_) => unreachable!(), - } - } +impl ExposedSeal for GraphSeal {} - fn outpoint_or(&self, default_txid: Txid) -> Outpoint { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.outpoint_or(default_txid), - XChain::Other(_) => unreachable!(), - } - } -} +impl ExposedSeal for GenesisSeal {} /* #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] @@ -117,47 +76,28 @@ impl<Seal: TxoSeal> TxoSeal for XChain<Seal> { pub struct SealPreimage(Bytes32); */ -impl From<XChain<GenesisSeal>> for XOutpoint { - #[inline] - fn from(seal: XChain<GenesisSeal>) -> Self { seal.to_outpoint() } -} - -impl XChain<GenesisSeal> { - pub fn transmutate(self) -> XChain<GraphSeal> { self.map_ref(|seal| seal.transmutate()) } - - /// Converts seal into a transaction outpoint. - #[inline] - pub fn to_outpoint(&self) -> XOutpoint { self.map_ref(GenesisSeal::to_outpoint).into() } -} - -impl<Id: SealTxid> XChain<BlindSeal<Id>> { - /// Converts revealed seal into concealed. - #[inline] - pub fn to_secret_seal(&self) -> XChain<SecretSeal> { self.conceal() } -} - #[cfg(test)] mod test { use amplify::hex::FromHex; - use bp::seals::txout::TxPtr; + use bp::seals::txout::{BlindSeal, TxPtr}; + use bp::Vout; use super::*; #[test] fn secret_seal_is_sha256d() { - let reveal = XChain::Bitcoin(BlindSeal { - method: CloseMethod::TapretFirst, + let reveal = BlindSeal { blinding: 54683213134637, txid: TxPtr::Txid( Txid::from_hex("646ca5c1062619e2a2d60771c9dfd820551fb773e4dc8c4ed67965a8d1fae839") .unwrap(), ), vout: Vout::from(2), - }); + }; let secret = reveal.to_secret_seal(); assert_eq!( secret.to_string(), - "bc:utxob:lD72u61i-sxCEKth-vqjH0mI-kcEwa1Q-fbnPLon-tDtXveO-keHh0" + "utxob:nBRVm39A-ioJydHE-ug2d90m-aZyfPI0-MCc0ZNM-oMXMs2O-opKQ7" ); assert_eq!(reveal.to_secret_seal(), reveal.conceal()) } diff --git a/src/operation/state.rs b/src/operation/state.rs index db230257..5edb64e6 100644 --- a/src/operation/state.rs +++ b/src/operation/state.rs @@ -23,32 +23,14 @@ use core::fmt::Debug; use core::hash::Hash; -use commit_verify::Conceal; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; -use crate::{ - ConcealedAttach, ConcealedData, ConcealedValue, RevealedAttach, RevealedData, RevealedValue, -}; - -/// Marker trait for types of state which are just a commitment to the actual -/// state data. -pub trait ConfidentialState: Debug + Eq + Copy { - fn state_type(&self) -> StateType; - fn state_commitment(&self) -> ConcealedState; -} +use crate::{RevealedAttach, RevealedData, RevealedValue}; /// Marker trait for types of state holding explicit state data. pub trait ExposedState: - Debug - + StrictDumb - + StrictEncode - + StrictDecode - + Conceal<Concealed = Self::Confidential> - + Eq - + Ord - + Clone + Debug + StrictDumb + StrictEncode + StrictDecode + Eq + Ord + Clone { - type Confidential: ConfidentialState + StrictEncode + StrictDecode + StrictDumb; fn state_type(&self) -> StateType; fn state_data(&self) -> RevealedState; } @@ -65,8 +47,7 @@ pub enum StateType { /// No state data Void, - /// Value-based state, i.e. which can be committed to with a Pedersen - /// commitment + /// Value-based state Fungible, /// State defined with custom data @@ -100,29 +81,3 @@ impl RevealedState { } } } - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "type") -)] -#[allow(clippy::large_enum_variant)] -pub enum ConcealedState { - Void, - Fungible(ConcealedValue), - Structured(ConcealedData), - Attachment(ConcealedAttach), -} - -impl ConfidentialState for ConcealedState { - fn state_type(&self) -> StateType { - match self { - ConcealedState::Void => StateType::Void, - ConcealedState::Fungible(_) => StateType::Fungible, - ConcealedState::Structured(_) => StateType::Structured, - ConcealedState::Attachment(_) => StateType::Attachment, - } - } - fn state_commitment(&self) -> ConcealedState { *self } -} diff --git a/src/operation/xchain.rs b/src/operation/xchain.rs deleted file mode 100644 index 91a606a1..00000000 --- a/src/operation/xchain.rs +++ /dev/null @@ -1,575 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky <orlovsky@lnp-bp.org> -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::cmp::Ordering; -use std::convert::Infallible; -use std::fmt::{Debug, Display, Formatter}; -use std::str::FromStr; -use std::{fmt, io}; - -use amplify::confinement::TinyOrdSet; -use bp::{Bp, Outpoint}; -use commit_verify::{Conceal, StrictHash}; -use strict_encoding::{ - DecodeError, DefineUnion, ReadTuple, ReadUnion, StrictDecode, StrictDumb, StrictEncode, - StrictEnum, StrictSum, StrictType, StrictUnion, TypedRead, TypedWrite, VariantError, - WriteUnion, -}; - -use crate::{OutputSeal, XOutputSeal, LIB_NAME_RGB_COMMIT}; - -pub const XCHAIN_BITCOIN_PREFIX: &str = "bc"; -pub const XCHAIN_LIQUID_PREFIX: &str = "lq"; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] -#[display(lowercase)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum Layer1 { - #[strict_type(dumb)] - Bitcoin = 0, - Liquid = 1, -} - -#[derive(Wrapper, WrapperMut, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)] -#[wrapper(Deref, FromStr, Display)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct XOutpoint(XChain<Outpoint>); - -impl From<XOutputSeal> for XOutpoint { - #[inline] - fn from(seal: XOutputSeal) -> Self { seal.to_outpoint() } -} - -impl XOutputSeal { - /// Converts seal into a transaction outpoint. - #[inline] - pub fn to_outpoint(&self) -> XOutpoint { self.map_ref(OutputSeal::to_outpoint).into() } -} - -#[cfg(feature = "serde")] -mod _serde { - use serde_crate::de::Error; - use serde_crate::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::*; - - impl Serialize for XOutpoint { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where S: Serializer { - if serializer.is_human_readable() { - serializer.serialize_str(&self.to_string()) - } else { - self.0.serialize(serializer) - } - } - } - - impl<'de> Deserialize<'de> for XOutpoint { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where D: Deserializer<'de> { - if deserializer.is_human_readable() { - let s = String::deserialize(deserializer)?; - Self::from_str(&s).map_err(D::Error::custom) - } else { - XChain::<Outpoint>::deserialize(deserializer).map(Self) - } - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] -#[display(lowercase)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum AltLayer1 { - #[strict_type(dumb)] - Liquid = 1, - // Abraxas = 0x10, - // Prime = 0x11, -} - -impl AltLayer1 { - pub fn layer1(&self) -> Layer1 { - match self { - AltLayer1::Liquid => Layer1::Liquid, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "chain", content = "data") -)] -pub enum Impossible {} - -impl TryFrom<u8> for Impossible { - type Error = VariantError<u8>; - - fn try_from(_: u8) -> Result<Self, Self::Error> { panic!("must not be instantiated") } -} -impl From<Impossible> for u8 { - fn from(_: Impossible) -> Self { unreachable!() } -} - -impl StrictDumb for Impossible { - fn strict_dumb() -> Self { panic!("must not be instantiated") } -} -impl StrictType for Impossible { - const STRICT_LIB_NAME: &'static str = LIB_NAME_RGB_COMMIT; -} -impl StrictSum for Impossible { - const ALL_VARIANTS: &'static [(u8, &'static str)] = &[]; - fn variant_name(&self) -> &'static str { unreachable!() } -} -impl StrictEnum for Impossible {} -impl StrictEncode for Impossible { - fn strict_encode<W: TypedWrite>(&self, _writer: W) -> io::Result<W> { unreachable!() } -} -impl StrictDecode for Impossible { - fn strict_decode(_reader: &mut impl TypedRead) -> Result<Self, DecodeError> { - panic!("must not be deserialized") - } -} - -impl Conceal for Impossible { - type Concealed = Self; - fn conceal(&self) -> Self::Concealed { unreachable!() } -} - -impl Display for Impossible { - fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result { unreachable!() } -} -impl FromStr for Impossible { - type Err = Infallible; - fn from_str(_: &str) -> Result<Self, Self::Err> { panic!("must not be parsed") } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AltLayer1Set(TinyOrdSet<AltLayer1>); - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "chain", content = "data") -)] -pub enum XChain<T, X = Impossible> { - Bitcoin(T), - - Liquid(T), - - Other(X), -} - -impl<T: Ord, X: Ord> PartialOrd for XChain<T, X> { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } -} - -impl<T: Ord, X: Ord> Ord for XChain<T, X> { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (Self::Bitcoin(t1), Self::Bitcoin(t2)) => t1.cmp(t2), - (Self::Liquid(t1), Self::Liquid(t2)) => t1.cmp(t2), - (Self::Bitcoin(_), _) => Ordering::Greater, - (_, Self::Bitcoin(_)) => Ordering::Less, - (Self::Liquid(_), _) => Ordering::Greater, - (_, Self::Liquid(_)) => Ordering::Less, - (Self::Other(x1), Self::Other(x2)) => x1.cmp(x2), - } - } -} - -impl<T: Conceal, X: Conceal> Conceal for XChain<T, X> { - type Concealed = XChain<T::Concealed, X::Concealed>; - - #[inline] - fn conceal(&self) -> Self::Concealed { self.map2_ref(|t| t.conceal(), |x| x.conceal()) } -} - -impl<T> StrictType for XChain<T> -where T: StrictDumb + StrictType -{ - const STRICT_LIB_NAME: &'static str = LIB_NAME_RGB_COMMIT; -} -impl<T> StrictSum for XChain<T> -where T: StrictDumb + StrictType -{ - const ALL_VARIANTS: &'static [(u8, &'static str)] = &[(0x00, "bitcoin"), (0x01, "liquid")]; - - fn variant_name(&self) -> &'static str { - match self { - XChain::Bitcoin(_) => Self::ALL_VARIANTS[0].1, - XChain::Liquid(_) => Self::ALL_VARIANTS[1].1, - XChain::Other(_) => unreachable!(), - } - } -} -impl<T> StrictUnion for XChain<T> where T: StrictDumb + StrictType {} -impl<T> StrictDumb for XChain<T> -where T: StrictDumb -{ - fn strict_dumb() -> Self { XChain::Bitcoin(strict_dumb!()) } -} -impl<T> StrictEncode for XChain<T> -where T: StrictDumb + StrictEncode -{ - fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> { - writer.write_union::<Self>(|w| { - let w = w - .define_newtype::<T>(vname!(Self::ALL_VARIANTS[0].1)) - .define_newtype::<T>(vname!(Self::ALL_VARIANTS[1].1)) - .complete(); - Ok(match self { - XChain::Bitcoin(t) => w.write_newtype(vname!(Self::ALL_VARIANTS[0].1), t)?, - XChain::Liquid(t) => w.write_newtype(vname!(Self::ALL_VARIANTS[1].1), t)?, - XChain::Other(_) => unreachable!(), - } - .complete()) - }) - } -} -impl<T> StrictDecode for XChain<T> -where T: StrictDumb + StrictDecode -{ - fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> { - reader.read_union(|field, r| match field.as_str() { - x if x == Self::ALL_VARIANTS[0].1 => { - r.read_tuple(|r| r.read_field().map(Self::Bitcoin)) - } - x if x == Self::ALL_VARIANTS[1].1 => r.read_tuple(|r| r.read_field().map(Self::Liquid)), - _ => unreachable!(), - }) - } -} - -impl<T> XChain<T, Impossible> { - pub fn layer1(&self) -> Layer1 { - match self { - XChain::Bitcoin(_) => Layer1::Bitcoin, - XChain::Liquid(_) => Layer1::Liquid, - XChain::Other(_) => unreachable!(), - } - } - - pub fn as_bp(&self) -> Bp<&T> - where for<'a> &'a T: StrictDumb + StrictEncode + StrictDecode { - match self { - XChain::Bitcoin(t) => Bp::Bitcoin(t), - XChain::Liquid(t) => Bp::Liquid(t), - XChain::Other(_) => unreachable!(), - } - } - - pub fn into_bp(self) -> Bp<T> - where T: StrictDumb + StrictEncode + StrictDecode { - match self { - XChain::Bitcoin(t) => Bp::Bitcoin(t), - XChain::Liquid(t) => Bp::Liquid(t), - XChain::Other(_) => unreachable!(), - } - } - - pub fn as_reduced_unsafe(&self) -> &T { - match self { - XChain::Bitcoin(t) | XChain::Liquid(t) => t, - XChain::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another. - pub fn map<U>(self, f: impl FnOnce(T) -> U) -> XChain<U> { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f(t)), - Self::Liquid(t) => XChain::Liquid(f(t)), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from a reference on internal type into another. - pub fn map_ref<U>(&self, f: impl FnOnce(&T) -> U) -> XChain<U> { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f(t)), - Self::Liquid(t) => XChain::Liquid(f(t)), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map<U, E>(self, f: impl FnOnce(T) -> Result<U, E>) -> Result<XChain<U>, E> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map_ref<U, E>(&self, f: impl FnOnce(&T) -> Result<U, E>) -> Result<XChain<U>, E> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<XChain<U>> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map_ref<U>(&self, f: impl FnOnce(&T) -> Option<U>) -> Option<XChain<U>> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Returns iterator over elements - pub fn iter<'i>( - &'i self, - ) -> Box<dyn Iterator<Item = XChain<<&'i T as IntoIterator>::Item>> + 'i> - where &'i T: IntoIterator { - match self { - XChain::Bitcoin(t) => Box::new(t.into_iter().map(XChain::Bitcoin)), - XChain::Liquid(t) => Box::new(t.into_iter().map(XChain::Liquid)), - Self::Other(_) => unreachable!(), - } - } -} - -impl<T, X> XChain<T, X> { - pub fn with(layer1: Layer1, data: impl Into<T>) -> Self { - match layer1 { - Layer1::Bitcoin => XChain::Bitcoin(data.into()), - Layer1::Liquid => XChain::Liquid(data.into()), - } - } - - pub fn is_bitcoin(&self) -> bool { matches!(self, XChain::Bitcoin(_)) } - pub fn is_liquid(&self) -> bool { matches!(self, XChain::Liquid(_)) } - pub fn is_bp(&self) -> bool { - match self { - XChain::Bitcoin(_) | XChain::Liquid(_) => true, - XChain::Other(_) => false, - } - } - - /// Maps the value from one internal type into another. - pub fn map2<U, Y>(self, f1: impl FnOnce(T) -> U, f2: impl FnOnce(X) -> Y) -> XChain<U, Y> { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f1(t)), - Self::Liquid(t) => XChain::Liquid(f1(t)), - Self::Other(x) => XChain::Other(f2(x)), - } - } - - /// Maps the value from a reference on internal type into another. - pub fn map2_ref<U, Y>( - &self, - f1: impl FnOnce(&T) -> U, - f2: impl FnOnce(&X) -> Y, - ) -> XChain<U, Y> { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f1(t)), - Self::Liquid(t) => XChain::Liquid(f1(t)), - Self::Other(x) => XChain::Other(f2(x)), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map2<U, Y, E>( - self, - f1: impl FnOnce(T) -> Result<U, E>, - f2: impl FnOnce(X) -> Result<Y, E>, - ) -> Result<XChain<U, Y>, E> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map2_ref<U, Y, E>( - &self, - f1: impl FnOnce(&T) -> Result<U, E>, - f2: impl FnOnce(&X) -> Result<Y, E>, - ) -> Result<XChain<U, Y>, E> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map2<U, Y>( - self, - f1: impl FnOnce(T) -> Option<U>, - f2: impl FnOnce(X) -> Option<Y>, - ) -> Option<XChain<U, Y>> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map2_ref<U, Y>( - &self, - f1: impl FnOnce(&T) -> Option<U>, - f2: impl FnOnce(&X) -> Option<Y>, - ) -> Option<XChain<U, Y>> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } -} - -impl<'a, T: Copy, X: Copy> XChain<&'a T, &'a X> { - pub fn copied(self) -> XChain<T, X> { self.map2(|t| *t, |x| *x) } -} - -impl<'a, T: Clone, X: Clone> XChain<&'a T, &'a X> { - pub fn cloned(self) -> XChain<T, X> { self.map2(T::clone, X::clone) } -} - -impl<T> XChain<Option<T>, Impossible> { - pub fn transpose(self) -> Option<XChain<T>> { - match self { - XChain::Bitcoin(inner) => inner.map(XChain::Bitcoin), - XChain::Liquid(inner) => inner.map(XChain::Liquid), - XChain::Other(_) => unreachable!(), - } - } -} - -impl<I: Iterator> Iterator for XChain<I, Impossible> { - type Item = XChain<<I as Iterator>::Item>; - - fn next(&mut self) -> Option<Self::Item> { - match self { - XChain::Bitcoin(t) => t.next().map(XChain::Bitcoin), - XChain::Liquid(t) => t.next().map(XChain::Liquid), - XChain::Other(_) => unreachable!(), - } - } -} - -#[derive(Clone, Debug, Display, Error, From)] -pub enum XChainParseError<E: Debug + Display> { - #[display("unknown chain prefix '{0}'; only 'bc:' and 'lq:' are currently supported")] - UnknownPrefix(String), - - #[from] - #[display(inner)] - Inner(E), -} - -impl<T: FromStr, X: FromStr> FromStr for XChain<T, X> -where - T: StrictDumb + StrictEncode + StrictDecode, - T::Err: Debug + Display, - X: StrictDumb + StrictEncode + StrictDecode, - X::Err: Debug + Display, -{ - type Err = XChainParseError<T::Err>; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - if let Some((prefix, s)) = s.split_once(':') { - match prefix { - XCHAIN_BITCOIN_PREFIX => s - .parse() - .map(XChain::Bitcoin) - .map_err(XChainParseError::from), - XCHAIN_LIQUID_PREFIX => s - .parse() - .map(XChain::Liquid) - .map_err(XChainParseError::from), - unknown => Err(XChainParseError::UnknownPrefix(unknown.to_owned())), - } - } else { - s.parse() - .map(XChain::Bitcoin) - .map_err(XChainParseError::from) - } - } -} - -impl<T: Display, X: Display> Display for XChain<T, X> -where - T: StrictDumb + StrictEncode + StrictDecode, - X: StrictDumb + StrictEncode + StrictDecode, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - XChain::Bitcoin(t) => write!(f, "{XCHAIN_BITCOIN_PREFIX}:{t}"), - XChain::Liquid(t) => write!(f, "{XCHAIN_LIQUID_PREFIX}:{t}"), - XChain::Other(x) => Display::fmt(x, f), - } - } -} diff --git a/src/schema/state.rs b/src/schema/state.rs index 27db9a15..d793e395 100644 --- a/src/schema/state.rs +++ b/src/schema/state.rs @@ -88,13 +88,6 @@ impl OwnedStateSchema { } } -/// Today we support only a single format of confidential data, because of the -/// limitations of the underlying secp256k1-zkp library: it works only with -/// u64 numbers. Nevertheless, homomorphic commitments can be created to -/// everything that has up to 256 bits and commutative arithmetics, so in the -/// future we plan to support more types. We reserve this possibility by -/// internally encoding [`ConfidentialFormat`] with the same type specification -/// details as used for [`DateFormat`] #[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Display)] #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] diff --git a/src/stl.rs b/src/stl.rs index bbc97c6f..7f158ed7 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -23,13 +23,14 @@ pub use aluvm::stl::aluvm_stl; pub use bp::bc::stl::bp_tx_stl; pub use bp::stl::bp_core_stl; +use bp::Txid; use commit_verify::stl::commit_verify_stl; use strict_types::stl::{std_stl, strict_types_stl}; use strict_types::typelib::LibBuilder; use strict_types::{CompileError, TypeLib}; use crate::validation::DbcProof; -use crate::vm::{GlobalOrd, XWitnessId}; +use crate::vm::GlobalOrd; use crate::{ Extension, Genesis, OpCommitment, Schema, TransitionBundle, LIB_NAME_RGB_COMMIT, LIB_NAME_RGB_LOGIC, @@ -37,10 +38,10 @@ use crate::{ /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_COMMIT: &str = - "stl:IFcnrPeI-TANxLfZ-feJax6Q-1TUM4Hq-AjI161s-3tbmxak#harvest-person-orion"; + "stl:n4BoS9Kd-oZ1mUgb-6Hqg9hY-q$JXa84-YoWed1a-!6AZCTM#raymond-open-organic"; /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_LOGIC: &str = - "stl:mqltqlPk-O9$pYOd-BACRI70-DOMJ6cp-TFvhcK1-ibrOI9U#import-boxer-seminar"; + "stl:HffUFU0Z-oNyZXNs-O8u1dRc-Q4Z5mOo-3bqPppu-A0f5iTo#permit-helena-lorenzo"; fn _rgb_commit_stl() -> Result<TypeLib, CompileError> { LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! { @@ -53,7 +54,7 @@ fn _rgb_commit_stl() -> Result<TypeLib, CompileError> { }) .transpile::<Schema>() .transpile::<Genesis>() - .transpile::<XWitnessId>() + .transpile::<Txid>() .transpile::<TransitionBundle>() .transpile::<Extension>() .transpile::<OpCommitment>() diff --git a/src/validation/consignment.rs b/src/validation/consignment.rs index 93800981..e69fc29d 100644 --- a/src/validation/consignment.rs +++ b/src/validation/consignment.rs @@ -26,10 +26,10 @@ use aluvm::library::{Lib, LibId}; use amplify::confinement::ConfinedOrdMap; +use bp::Txid; use strict_types::TypeSystem; use super::EAnchor; -use crate::vm::XWitnessId; use crate::{ AssignmentType, AssignmentsRef, BundleId, ContractId, Extension, ExtensionType, Genesis, GlobalState, GraphSeal, Inputs, Metadata, OpFullType, OpId, OpType, Operation, Schema, @@ -162,7 +162,7 @@ impl<'consignment, C: ConsignmentApi> CheckedConsignment<'consignment, C> { pub fn new(consignment: &'consignment C) -> Self { Self(consignment) } } -impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'consignment, C> { +impl<C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'_, C> { fn schema(&self) -> &Schema { self.0.schema() } fn types(&self) -> &TypeSystem { self.0.types() } @@ -183,11 +183,9 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con .filter(|b| b.bundle_id() == bundle_id) } - fn anchor(&self, bundle_id: BundleId) -> Option<(XWitnessId, &EAnchor)> { - self.0.anchor(bundle_id) - } + fn anchor(&self, bundle_id: BundleId) -> Option<(Txid, &EAnchor)> { self.0.anchor(bundle_id) } - fn op_witness_id(&self, opid: OpId) -> Option<XWitnessId> { self.0.op_witness_id(opid) } + fn op_witness_id(&self, opid: OpId) -> Option<Txid> { self.0.op_witness_id(opid) } } /// Trait defining common data access API for all storage-related RGB structures @@ -222,8 +220,8 @@ pub trait ConsignmentApi { fn bundle(&self, bundle_id: BundleId) -> Option<&TransitionBundle>; /// Returns a grip given a bundle id. - fn anchor(&self, bundle_id: BundleId) -> Option<(XWitnessId, &EAnchor)>; + fn anchor(&self, bundle_id: BundleId) -> Option<(Txid, &EAnchor)>; /// Returns witness id for a given operation. - fn op_witness_id(&self, opid: OpId) -> Option<XWitnessId>; + fn op_witness_id(&self, opid: OpId) -> Option<Txid>; } diff --git a/src/validation/logic.rs b/src/validation/logic.rs index 0afd7f93..d2dbddcf 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -36,10 +36,10 @@ use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi}; use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, OrdOpRef, RgbIsa, VmContext}; use crate::{ - validation, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, - ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, - GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, Operation, Opout, - OwnedStateSchema, RevealedState, Schema, StateType, Transition, TypedAssigns, Valencies, + validation, Assign, AssignmentType, Assignments, AssignmentsRef, ExposedSeal, ExposedState, + Extension, GlobalState, GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, + Metadata, OpId, Operation, Opout, OwnedStateSchema, RevealedState, Schema, Transition, + TypedAssigns, Valencies, }; impl Schema { @@ -69,31 +69,16 @@ impl Schema { validator, ty, ) = match op { - OrdOpRef::Genesis(genesis) => { - for id in genesis.asset_tags.keys() { - if !matches!(self.owned_types.get(id), Some(OwnedStateSchema::Fungible(_))) { - status.add_failure(validation::Failure::AssetTagNoState(*id)); - } - } - for (id, ss) in &self.owned_types { - if ss.state_type() == StateType::Fungible - && !genesis.asset_tags.contains_key(id) - { - status.add_failure(validation::Failure::FungibleStateNoTag(*id)); - } - } - - ( - &self.genesis.metadata, - &self.genesis.globals, - &empty_assign_schema, - &empty_valency_schema, - &self.genesis.assignments, - &self.genesis.valencies, - self.genesis.validator, - None::<u16>, - ) - } + OrdOpRef::Genesis(_) => ( + &self.genesis.metadata, + &self.genesis.globals, + &empty_assign_schema, + &empty_valency_schema, + &self.genesis.assignments, + &self.genesis.valencies, + self.genesis.validator, + None::<u16>, + ), OrdOpRef::Transition( Transition { transition_type, .. @@ -199,7 +184,6 @@ impl Schema { let op_info = OpInfo::with(opid, &op, &prev_state, &redeemed); let context = VmContext { contract_id: genesis.contract_id(), - asset_tags: &genesis.asset_tags, op_info, contract_state, }; @@ -581,40 +565,6 @@ impl OwnedStateSchema { ) -> validation::Status { let mut status = validation::Status::new(); match data { - Assign::Confidential { state, .. } | Assign::ConfidentialState { state, .. } => { - match (self, state.state_commitment()) { - (OwnedStateSchema::Declarative, ConcealedState::Void) => {} - (OwnedStateSchema::Fungible(_), ConcealedState::Fungible(value)) => { - // [SECURITY-CRITICAL]: Bulletproofs validation - if let Err(err) = value.verify_range_proof() { - status.add_failure(validation::Failure::BulletproofsInvalid( - opid, - state_type, - err.to_string(), - )); - } - } - (OwnedStateSchema::Structured(_), ConcealedState::Structured(_)) => { - status.add_warning(validation::Warning::UncheckableConfidentialState( - opid, state_type, - )); - } - (OwnedStateSchema::Attachment(_), ConcealedState::Attachment(_)) => { - status.add_warning(validation::Warning::UncheckableConfidentialState( - opid, state_type, - )); - } - // all other options are mismatches - (state_schema, found) => { - status.add_failure(validation::Failure::StateTypeMismatch { - opid, - state_type, - expected: state_schema.state_type(), - found: found.state_type(), - }); - } - } - } Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => { match (self, state.state_data()) { (OwnedStateSchema::Declarative, RevealedState::Void) => {} diff --git a/src/validation/status.rs b/src/validation/status.rs index f77c6a0a..ef074c43 100644 --- a/src/validation/status.rs +++ b/src/validation/status.rs @@ -24,15 +24,15 @@ use core::ops::AddAssign; use std::fmt::{self, Display, Formatter}; use amplify::num::u24; +use bp::seals::txout::CloseMethod; +use bp::Txid; use commit_verify::mpc::InvalidProof; use strict_types::SemId; use crate::schema::{self, SchemaId}; use crate::validation::WitnessResolverError; -use crate::vm::XWitnessId; use crate::{ - BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, Opout, StateType, Vin, - XGraphSeal, XOutputSeal, + BundleId, ChainNet, ContractId, OccurrencesMismatch, OpFullType, OpId, Opout, StateType, Vin, }; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)] @@ -162,9 +162,13 @@ impl Status { )] #[display(doc_comments)] pub enum Failure { - /// the contract network doesn't match (validator runs in testnet={0} + /// the contract chain-network pair doesn't match (validator runs in chain_net={0} /// configuration). - NetworkMismatch(bool), + ContractChainNetMismatch(ChainNet), + + /// the resolver chain-network pair doesn't match (validator runs in chain_net={0} + /// configuration). + ResolverChainNetMismatch(ChainNet), /// schema {actual} provided for the consignment validation doesn't match /// schema {expected} used by the contract. This means that the consignment @@ -248,9 +252,11 @@ pub enum Failure { /// bundle {0} public witness {1} is not known to the resolver; validation /// stopped since operations can't be consensus-ordered. The resolver /// responded with error {2} - WitnessUnresolved(BundleId, XWitnessId, WitnessResolverError), + WitnessUnresolved(BundleId, Txid, WitnessResolverError), /// operation {0} is under a different contract {1}. ContractMismatch(OpId, ContractId), + /// opout {0} appears more than once as input + DoubleSpend(Opout), // Errors checking bundle commitments /// transition bundle {0} references state transition {1} which is not @@ -258,17 +264,10 @@ pub enum Failure { BundleExtraTransition(BundleId, OpId), /// transition bundle {0} references non-existing input in witness {2} for /// the state transition {1}. - BundleInvalidInput(BundleId, OpId, XWitnessId), + BundleInvalidInput(BundleId, OpId, Txid), /// transition bundle {0} doesn't commit to the input {1} in the witness {2} /// which is an input of the state transition {3}. - BundleInvalidCommitment(BundleId, Vin, XWitnessId, OpId), - - // Errors checking asset tags - /// asset type provided in genesis references unknown fungible state of type - /// {0}. - AssetTagNoState(schema::AssignmentType), - /// fungible state {0} has no asset tag defined. - FungibleStateNoTag(schema::AssignmentType), + BundleInvalidCommitment(BundleId, Vin, Txid, OpId), // Errors checking seal closing /// transition {opid} references state type {state_type} absent in the @@ -285,26 +284,21 @@ pub enum Failure { ConfidentialSeal(Opout), /// bundle {0} public witness {1} is not known to the resolver. Resolver /// reported error {2} - SealNoPubWitness(BundleId, XWitnessId, WitnessResolverError), - /// witness layer 1 {anchor} doesn't match seal definition {seal}. - SealWitnessLayer1Mismatch { seal: Layer1, anchor: Layer1 }, - /// seal {1} is defined on {0} which is not in the set of layers allowed - /// by the contract genesis. - SealLayerMismatch(Layer1, XGraphSeal), - /// seal {1} has a different closing method from the bundle {0} requirement. - SealInvalidMethod(BundleId, XOutputSeal), + SealNoPubWitness(BundleId, Txid, WitnessResolverError), /// transition bundle {0} doesn't close seal with the witness {1}. Details: /// {2} - SealsInvalid(BundleId, XWitnessId, String), + SealsInvalid(BundleId, Txid, String), /// single-use seals for the operation {0} were not validated, which /// probably indicates unanchored state transition. SealsUnvalidated(OpId), - /// anchor provides different type of DBC proof than required by the bundle - /// {0}. - AnchorMethodMismatch(BundleId), /// transition bundle {0} is not properly anchored to the witness {1}. /// Details: {2} - MpcInvalid(BundleId, XWitnessId, InvalidProof), + MpcInvalid(BundleId, Txid, InvalidProof), + /// witness transaction {0} has no taproot or OP_RETURN output. + NoDbcOutput(Txid), + /// first DBC-compatible output of witness transaction {0} doesn't match the provided proof + /// type ({1}) + InvalidProofType(Txid, CloseMethod), // State extensions errors /// valency {valency} redeemed by state extension {opid} references @@ -347,8 +341,6 @@ pub enum Failure { expected: schema::FungibleType, found: schema::FungibleType, }, - /// invalid bulletproofs in {0}:{1}: {2} - BulletproofsInvalid(OpId, schema::AssignmentType, String), /// evaluation of AluVM script for operation {0} has failed with the code /// {1:?} and message {2:?}. ScriptFailure(OpId, Option<u8>, Option<String>), @@ -368,10 +360,6 @@ pub enum Failure { )] #[display(doc_comments)] pub enum Warning { - /// operation {0} contains state in assignment {1} which is confidential and - /// thus was not validated. - UncheckableConfidentialState(OpId, schema::AssignmentType), - /// Custom warning by external services on top of RGB Core. #[display(inner)] Custom(String), diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 941bc14f..20dba826 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -24,20 +24,19 @@ use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet}; use std::rc::Rc; -use bp::dbc::{Anchor, Proof}; -use bp::seals::txout::{TxoSeal, Witness}; -use bp::{dbc, Outpoint}; +use bp::dbc::Anchor; +use bp::seals::txout::{CloseMethod, Witness}; +use bp::{dbc, Outpoint, Tx, Txid}; use commit_verify::mpc; use single_use_seals::SealWitness; use super::status::Failure; use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, OpRef, Status, Validity}; -use crate::vm::{ - ContractStateAccess, ContractStateEvolve, OrdOpRef, WitnessOrd, XWitnessId, XWitnessTx, -}; +use crate::operation::seal::ExposedSeal; +use crate::vm::{ContractStateAccess, ContractStateEvolve, OrdOpRef, WitnessOrd}; use crate::{ - validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpType, Operation, Opout, Schema, - SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, + validation, BundleId, ChainNet, ContractId, OpId, OpType, Operation, Opout, OutputSeal, Schema, + SchemaId, TransitionBundle, }; #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] @@ -49,43 +48,40 @@ use crate::{ )] pub enum WitnessResolverError { /// actual witness id {actual} doesn't match expected id {expected}. - IdMismatch { - actual: XWitnessId, - expected: XWitnessId, - }, + IdMismatch { actual: Txid, expected: Txid }, /// witness {0} does not exist. - Unknown(XWitnessId), + Unknown(Txid), /// unable to retrieve witness {0}, {1} - Other(XWitnessId, String), + Other(Txid, String), + /// resolver is for another chain-network pair + WrongChainNet, } pub trait ResolveWitness { // TODO: Return with SPV proof data - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result<XWitnessTx, WitnessResolverError>; + fn resolve_pub_witness(&self, witness_id: Txid) -> Result<Tx, WitnessResolverError>; - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result<WitnessOrd, WitnessResolverError>; + fn resolve_pub_witness_ord(&self, witness_id: Txid) + -> Result<WitnessOrd, WitnessResolverError>; + + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), WitnessResolverError>; } impl<T: ResolveWitness> ResolveWitness for &T { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result<XWitnessTx, WitnessResolverError> { + fn resolve_pub_witness(&self, witness_id: Txid) -> Result<Tx, WitnessResolverError> { ResolveWitness::resolve_pub_witness(*self, witness_id) } fn resolve_pub_witness_ord( &self, - witness_id: XWitnessId, + witness_id: Txid, ) -> Result<WitnessOrd, WitnessResolverError> { ResolveWitness::resolve_pub_witness_ord(*self, witness_id) } + + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), WitnessResolverError> { + ResolveWitness::check_chain_net(*self, chain_net) + } } struct CheckedWitnessResolver<R: ResolveWitness> { @@ -97,12 +93,9 @@ impl<R: ResolveWitness> From<R> for CheckedWitnessResolver<R> { } impl<R: ResolveWitness> ResolveWitness for CheckedWitnessResolver<R> { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result<XWitnessTx, WitnessResolverError> { + fn resolve_pub_witness(&self, witness_id: Txid) -> Result<Tx, WitnessResolverError> { let witness = self.inner.resolve_pub_witness(witness_id)?; - let actual_id = witness.witness_id(); + let actual_id = witness.txid(); if actual_id != witness_id { return Err(WitnessResolverError::IdMismatch { actual: actual_id, @@ -115,10 +108,14 @@ impl<R: ResolveWitness> ResolveWitness for CheckedWitnessResolver<R> { #[inline] fn resolve_pub_witness_ord( &self, - witness_id: XWitnessId, + witness_id: Txid, ) -> Result<WitnessOrd, WitnessResolverError> { self.inner.resolve_pub_witness_ord(witness_id) } + + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), WitnessResolverError> { + self.inner.check_chain_net(chain_net) + } } pub struct Validator< @@ -134,10 +131,11 @@ pub struct Validator< schema_id: SchemaId, contract_id: ContractId, - layers1: BTreeSet<Layer1>, + chain_net: ChainNet, contract_state: Rc<RefCell<S>>, validated_op_seals: RefCell<BTreeSet<OpId>>, + input_assignments: RefCell<BTreeSet<Opout>>, resolver: CheckedWitnessResolver<&'resolver R>, } @@ -160,20 +158,20 @@ impl< let genesis = consignment.genesis(); let contract_id = genesis.contract_id(); let schema_id = genesis.schema_id; + let chain_net = genesis.chain_net; // Prevent repeated validation of single-use seals let validated_op_seals = RefCell::new(BTreeSet::<OpId>::new()); - - let mut layers1 = bset! { Layer1::Bitcoin }; - layers1.extend(genesis.alt_layers1.iter().map(AltLayer1::layer1)); + let input_transitions = RefCell::new(BTreeSet::<Opout>::new()); Self { consignment, status: RefCell::new(status), schema_id, contract_id, - layers1, + chain_net, validated_op_seals, + input_assignments: input_transitions, resolver: CheckedWitnessResolver::from(resolver), contract_state: Rc::new(RefCell::new(S::init(context))), } @@ -191,17 +189,24 @@ impl< pub fn validate( consignment: &'consignment C, resolver: &'resolver R, - testnet: bool, + chain_net: ChainNet, context: S::Context<'_>, ) -> Status { let mut validator = Self::init(consignment, resolver, context); - // If the network mismatches there is no point in validating the contract since - // all witness transactions will be missed. - if testnet != validator.consignment.genesis().testnet { + // If the chain-network pair doesn't match there is no point in validating the contract + // since all witness transactions will be missed. + if validator.chain_net != chain_net { validator .status .borrow_mut() - .add_failure(Failure::NetworkMismatch(testnet)); + .add_failure(Failure::ContractChainNetMismatch(chain_net)); + return validator.status.into_inner(); + } + if resolver.check_chain_net(chain_net).is_err() { + validator + .status + .borrow_mut() + .add_failure(Failure::ResolverChainNetMismatch(chain_net)); return validator.status.into_inner(); } @@ -280,7 +285,7 @@ impl< } }; for op in bundle.known_transitions.values() { - ops.insert(OrdOpRef::Transition(op, witness_id, witness_ord)); + ops.insert(OrdOpRef::Transition(op, witness_id, witness_ord, bundle_id)); for input in &op.inputs { // We will error in `validate_operations` below on the absent extension from the // consignment. @@ -392,17 +397,10 @@ impl< continue; }; - // [VALIDATION]: We validate that the seals were properly defined on BP-type layers - let (seals, input_map) = self.validate_seal_definitions(witness_id.layer1(), bundle); - - if anchor.dbc_proof.method() != bundle.close_method { - self.status - .borrow_mut() - .add_failure(Failure::AnchorMethodMismatch(bundle_id)); - continue; - } + // [VALIDATION]: We validate that the seals were properly defined on BP-type layer + let (seals, input_map) = self.validate_seal_definitions(bundle); - // [VALIDATION]: We validate that the seals were properly closed on BP-type layers + // [VALIDATION]: We validate that the seals were properly closed on BP-type layer let Some(witness_tx) = self.validate_seal_commitments(&seals, bundle_id, witness_id, anchor) else { @@ -422,10 +420,10 @@ impl< &self, bundle_id: BundleId, bundle: &TransitionBundle, - pub_witness: XWitnessTx, - input_map: BTreeMap<OpId, BTreeSet<XOutpoint>>, + pub_witness: Tx, + input_map: BTreeMap<OpId, BTreeSet<Outpoint>>, ) { - let witness_id = pub_witness.witness_id(); + let witness_id = pub_witness.txid(); for (vin, opid) in &bundle.input_map { let Some(outpoints) = input_map.get(opid) else { self.status @@ -433,15 +431,13 @@ impl< .add_failure(Failure::BundleExtraTransition(bundle_id, *opid)); continue; }; - let layer1 = pub_witness.layer1(); - let pub_witness = pub_witness.as_reduced_unsafe(); let Some(input) = pub_witness.inputs.get(vin.to_usize()) else { self.status .borrow_mut() .add_failure(Failure::BundleInvalidInput(bundle_id, *opid, witness_id)); continue; }; - if !outpoints.contains(&XChain::with(layer1, input.prev_output)) { + if !outpoints.contains(&input.prev_output) { self.status .borrow_mut() .add_failure(Failure::BundleInvalidCommitment( @@ -455,11 +451,11 @@ impl< /// bitcoin commitments with opret and tapret schema. fn validate_seal_commitments( &self, - seals: impl AsRef<[XOutputSeal]>, + seals: impl AsRef<[OutputSeal]>, bundle_id: BundleId, - witness_id: XWitnessId, + witness_id: Txid, anchor: &EAnchor, - ) -> Option<XWitnessTx> { + ) -> Option<Tx> { // Check that the anchor is committed into a transaction spending all the // transition inputs. // Here the method can do SPV proof instead of querying the indexer. The SPV @@ -482,21 +478,13 @@ impl< } Ok(pub_witness) => { let seals = seals.as_ref(); - for seal in seals - .iter() - .filter(|seal| seal.method() != anchor.dbc_proof.method()) - { - self.status - .borrow_mut() - .add_failure(Failure::SealInvalidMethod(bundle_id, *seal)); - } match anchor.clone() { EAnchor { mpc_proof, dbc_proof: DbcProof::Tapret(tapret), .. } => { - let witness = pub_witness.clone().map(|tx| Witness::with(tx, tapret)); + let witness = Witness::with(pub_witness.clone(), tapret); self.validate_seal_closing(seals, bundle_id, witness, mpc_proof) } EAnchor { @@ -504,7 +492,7 @@ impl< dbc_proof: DbcProof::Opret(opret), .. } => { - let witness = pub_witness.clone().map(|tx| Witness::with(tx, opret)); + let witness = Witness::with(pub_witness.clone(), opret); self.validate_seal_closing(seals, bundle_id, witness, mpc_proof) } } @@ -516,14 +504,12 @@ impl< /// Single-use-seal definition validation. /// - /// Takes state transition, extracts all seals from its inputs and makes - /// sure they are defined or a correct layer1. + /// Takes state transition, extracts all seals from its inputs and validates them. fn validate_seal_definitions( &self, - layer1: Layer1, bundle: &TransitionBundle, - ) -> (Vec<XOutputSeal>, BTreeMap<OpId, BTreeSet<XOutpoint>>) { - let mut input_map: BTreeMap<OpId, BTreeSet<XOutpoint>> = bmap!(); + ) -> (Vec<OutputSeal>, BTreeMap<OpId, BTreeSet<Outpoint>>) { + let mut input_map: BTreeMap<OpId, BTreeSet<Outpoint>> = bmap!(); let mut seals = vec![]; for (opid, transition) in &bundle.known_transitions { let opid = *opid; @@ -538,6 +524,11 @@ impl< // outputs. for input in &transition.inputs { let Opout { op, ty, no } = input.prev_out; + if !self.input_assignments.borrow_mut().insert(input.prev_out) { + self.status + .borrow_mut() + .add_failure(Failure::DoubleSpend(input.prev_out)); + } let Some(prev_op) = self.consignment.operation(op) else { // Node, referenced as the ancestor, was not found in the consignment. @@ -572,22 +563,6 @@ impl< continue; }; - if seal.layer1() != layer1 { - self.status - .borrow_mut() - .add_failure(Failure::SealWitnessLayer1Mismatch { - seal: seal.layer1(), - anchor: layer1, - }); - continue; - } - if !self.layers1.contains(&seal.layer1()) { - self.status - .borrow_mut() - .add_failure(Failure::SealLayerMismatch(seal.layer1(), seal)); - continue; - } - let seal = if prev_op.op_type() == OpType::StateTransition { let Some(witness_id) = self.consignment.op_witness_id(op) else { self.status @@ -595,19 +570,7 @@ impl< .add_failure(Failure::OperationAbsent(op)); continue; }; - - match seal.try_to_output_seal(witness_id) { - Ok(seal) => seal, - Err(_) => { - self.status.borrow_mut().add_failure( - Failure::SealWitnessLayer1Mismatch { - seal: seal.layer1(), - anchor: witness_id.layer1(), - }, - ); - continue; - } - } + seal.to_output_seal_or_default(witness_id) } else { seal.to_output_seal() .expect("genesis and state extensions must have explicit seals") @@ -617,7 +580,7 @@ impl< input_map .entry(opid) .or_default() - .insert(seal.map(|seal| Outpoint::new(seal.txid, seal.vout)).into()); + .insert(Outpoint::new(seal.txid, seal.vout)); } } (seals, input_map) @@ -637,14 +600,14 @@ impl< &self, seals: impl IntoIterator<Item = &'seal Seal>, bundle_id: BundleId, - witness: XChain<Witness<Dbc>>, + witness: Witness<Dbc>, mpc_proof: mpc::MerkleProof, ) where - XChain<Witness<Dbc>>: SealWitness<Seal, Message = mpc::Commitment>, + Witness<Dbc>: SealWitness<Seal, Message = mpc::Commitment>, { let message = mpc::Message::from(bundle_id); - let witness_id = witness.witness_id(); - let anchor = Anchor::new(mpc_proof, witness.as_reduced_unsafe().proof.clone()); + let witness_id = witness.txid; + let anchor = Anchor::new(mpc_proof, witness.proof.clone()); // [VALIDATION]: Checking anchor MPC commitment match anchor.convolve(self.contract_id, message) { Err(err) => { @@ -655,6 +618,28 @@ impl< .add_failure(Failure::MpcInvalid(bundle_id, witness_id, err)); } Ok(commitment) => { + // [VALIDATION]: Verify commitment + let Some(output) = witness + .tx + .outputs() + .find(|out| out.script_pubkey.is_op_return() || out.script_pubkey.is_p2tr()) + else { + self.status + .borrow_mut() + .add_failure(Failure::NoDbcOutput(witness_id)); + return; + }; + let output_method = if output.script_pubkey.is_op_return() { + CloseMethod::OpretFirst + } else { + CloseMethod::TapretFirst + }; + let proof_method = witness.proof.method(); + if proof_method != output_method { + self.status + .borrow_mut() + .add_failure(Failure::InvalidProofType(witness_id, proof_method)); + } // [VALIDATION]: CHECKING SINGLE-USE-SEALS witness .verify_many_seals(seals, &commitment) diff --git a/src/vm/contract.rs b/src/vm/contract.rs index e0d5534f..29ee66dd 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -29,113 +29,17 @@ use std::rc::Rc; use amplify::confinement; use amplify::num::u24; -use bp::seals::txout::{CloseMethod, ExplicitSeal, VerifyError, Witness}; -use bp::{dbc, Tx, Txid}; +use bp::{Outpoint, Txid}; use chrono::{MappedLocalTime, TimeZone, Utc}; -use commit_verify::mpc; -use single_use_seals::SealWitness; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::{ - AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, - ExposedSeal, Extension, ExtensionType, FungibleState, Genesis, GlobalState, GlobalStateType, - GraphSeal, Impossible, Inputs, Layer1, Metadata, OpFullType, OpId, OpType, Operation, - Transition, TransitionType, TxoSeal, TypedAssigns, Valencies, XChain, XOutpoint, XOutputSeal, - LIB_NAME_RGB_LOGIC, + AssignmentType, Assignments, AssignmentsRef, AttachState, BundleId, ContractId, DataState, + Extension, ExtensionType, FungibleState, Genesis, GlobalState, GlobalStateType, GraphSeal, + Inputs, Layer1, Metadata, OpFullType, OpId, OpType, Operation, Transition, TransitionType, + TypedAssigns, Valencies, LIB_NAME_RGB_LOGIC, }; -pub type XWitnessId = XChain<Txid>; - -pub type XWitnessTx<X = Impossible> = XChain<Tx, X>; - -impl XWitnessTx { - pub fn witness_id(&self) -> XWitnessId { - match self { - Self::Bitcoin(tx) => XWitnessId::Bitcoin(tx.txid()), - Self::Liquid(tx) => XWitnessId::Liquid(tx.txid()), - Self::Other(_) => unreachable!(), - } - } -} - -impl<Dbc: dbc::Proof> XChain<Witness<Dbc>> { - pub fn witness_id(&self) -> XWitnessId { - match self { - Self::Bitcoin(w) => XWitnessId::Bitcoin(w.txid), - Self::Liquid(w) => XWitnessId::Liquid(w.txid), - Self::Other(_) => unreachable!(), - } - } -} - -impl<Dbc: dbc::Proof, Seal: TxoSeal> SealWitness<Seal> for XChain<Witness<Dbc>> { - type Message = mpc::Commitment; - type Error = VerifyError<Dbc::Error>; - - fn verify_seal(&self, seal: &Seal, msg: &Self::Message) -> Result<(), Self::Error> { - match self { - Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_seal(seal, msg), - Self::Other(_) => unreachable!(), - } - } - - fn verify_many_seals<'seal>( - &self, - seals: impl IntoIterator<Item = &'seal Seal>, - msg: &Self::Message, - ) -> Result<(), Self::Error> - where - Seal: 'seal, - { - match self { - Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_many_seals(seals, msg), - Self::Other(_) => unreachable!(), - } - } -} - -impl<U: ExposedSeal> XChain<U> { - pub fn method(self) -> CloseMethod - where U: TxoSeal { - match self { - XChain::Bitcoin(seal) => seal.method(), - XChain::Liquid(seal) => seal.method(), - XChain::Other(_) => unreachable!(), - } - } - - #[inline] - pub fn to_output_seal(self) -> Option<XOutputSeal> - where U: TxoSeal { - Some(match self { - XChain::Bitcoin(seal) => { - let outpoint = seal.outpoint()?; - XChain::Bitcoin(ExplicitSeal::new(seal.method(), outpoint)) - } - XChain::Liquid(seal) => { - let outpoint = seal.outpoint()?; - XChain::Liquid(ExplicitSeal::new(seal.method(), outpoint)) - } - XChain::Other(_) => unreachable!(), - }) - } - - pub fn try_to_output_seal(self, witness_id: XWitnessId) -> Result<XOutputSeal, Self> - where U: TxoSeal { - self.to_output_seal() - .or(match (self, witness_id) { - (XChain::Bitcoin(seal), XWitnessId::Bitcoin(txid)) => { - Some(XChain::Bitcoin(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) - } - (XChain::Liquid(seal), XWitnessId::Liquid(txid)) => { - Some(XChain::Liquid(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) - } - _ => None, - }) - .ok_or(self) - } -} - /// The type is used during validation and computing a contract state. It /// combines both the operation with the information required for its ordering /// in the contract history (via construction of [`OpOrd`]) according to the @@ -144,20 +48,20 @@ impl<U: ExposedSeal> XChain<U> { pub enum OrdOpRef<'op> { #[from] Genesis(&'op Genesis), - Transition(&'op Transition, XWitnessId, WitnessOrd), - Extension(&'op Extension, XWitnessId, WitnessOrd), + Transition(&'op Transition, Txid, WitnessOrd, BundleId), + Extension(&'op Extension, Txid, WitnessOrd), } -impl<'op> PartialOrd for OrdOpRef<'op> { +impl PartialOrd for OrdOpRef<'_> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } -impl<'op> Ord for OrdOpRef<'op> { +impl Ord for OrdOpRef<'_> { fn cmp(&self, other: &Self) -> Ordering { self.op_ord().cmp(&other.op_ord()) } } -impl<'op> OrdOpRef<'op> { - pub fn witness_id(&self) -> Option<XWitnessId> { +impl OrdOpRef<'_> { + pub fn witness_id(&self) -> Option<Txid> { match self { OrdOpRef::Genesis(_) => None, OrdOpRef::Transition(_, witness_id, ..) | OrdOpRef::Extension(_, witness_id, ..) => { @@ -166,10 +70,17 @@ impl<'op> OrdOpRef<'op> { } } + pub fn bundle_id(&self) -> Option<BundleId> { + match self { + OrdOpRef::Genesis(_) | OrdOpRef::Extension(..) => None, + OrdOpRef::Transition(_, _, _, bundle_id) => Some(*bundle_id), + } + } + pub fn op_ord(&self) -> OpOrd { match self { OrdOpRef::Genesis(_) => OpOrd::Genesis, - OrdOpRef::Transition(op, _, witness_ord) => OpOrd::Transition { + OrdOpRef::Transition(op, _, witness_ord, _) => OpOrd::Transition { witness: *witness_ord, ty: op.transition_type, nonce: op.nonce, @@ -414,6 +325,8 @@ impl Display for WitnessPos { serde(crate = "serde_crate", rename_all = "camelCase") )] pub enum WitnessOrd { + /// Witness transaction must be ignored by the update witnesses process. + Ignored, /// Witness transaction must be excluded from the state processing. /// /// Cases for the exclusion: @@ -674,23 +587,23 @@ pub trait ContractStateAccess: Debug { ty: GlobalStateType, ) -> Result<GlobalContractState<impl GlobalStateIter>, UnknownGlobalStateType>; - fn rights(&self, outpoint: XOutpoint, ty: AssignmentType) -> u32; + fn rights(&self, outpoint: Outpoint, ty: AssignmentType) -> u32; fn fungible( &self, - outpoint: XOutpoint, + outpoint: Outpoint, ty: AssignmentType, ) -> impl DoubleEndedIterator<Item = FungibleState>; fn data( &self, - outpoint: XOutpoint, + outpoint: Outpoint, ty: AssignmentType, ) -> impl DoubleEndedIterator<Item = impl Borrow<DataState>>; fn attach( &self, - outpoint: XOutpoint, + outpoint: Outpoint, ty: AssignmentType, ) -> impl DoubleEndedIterator<Item = impl Borrow<AttachState>>; } @@ -705,7 +618,6 @@ pub trait ContractStateEvolve { pub struct VmContext<'op, S: ContractStateAccess> { pub contract_id: ContractId, - pub asset_tags: &'op AssetTags, pub op_info: OpInfo<'op>, pub contract_state: Rc<RefCell<S>>, } diff --git a/src/vm/macroasm.rs b/src/vm/macroasm.rs index 0422e4a0..e28aca82 100644 --- a/src/vm/macroasm.rs +++ b/src/vm/macroasm.rs @@ -33,14 +33,14 @@ macro_rules! rgbasm { #[macro_export] macro_rules! isa_instr { - (pcvs $no:ident) => {{ - RgbIsa::Contract(ContractOp::Pcvs($no)) + (svs $no:ident) => {{ + RgbIsa::Contract(ContractOp::Svs($no)) }}; - (pcas $no:ident) => {{ - RgbIsa::Contract(ContractOp::Pcas($no)) + (sas $no:ident) => {{ + RgbIsa::Contract(ContractOp::Sas($no)) }}; - (pcps $no:ident) => {{ - RgbIsa::Contract(ContractOp::Pcps($no)) + (sps $no:ident) => {{ + RgbIsa::Contract(ContractOp::Sps($no)) }}; (cng $t:ident,a8[$a_idx:literal]) => {{ RgbIsa::Contract(ContractOp::CnG($t, Reg32::from(u5::with($a_idx)))) diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 89ccf6ad..5cda4e8d 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -35,7 +35,7 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, - OpOrd, OrdOpRef, UnknownGlobalStateType, WitnessOrd, WitnessPos, XWitnessId, XWitnessTx, + OpOrd, OrdOpRef, UnknownGlobalStateType, WitnessOrd, WitnessPos, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index 040277ec..930a312d 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -33,14 +33,10 @@ use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; use aluvm::reg::{CoreRegs, Reg, Reg16, Reg32, RegA, RegS}; use amplify::num::{u24, u3, u4}; use amplify::Wrapper; -use commit_verify::CommitVerify; use super::opcodes::*; use super::{ContractStateAccess, VmContext}; -use crate::{ - Assign, AssignmentType, BlindingFactor, GlobalStateType, MetaType, PedersenCommitment, - RevealedValue, TypedAssigns, -}; +use crate::{Assign, AssignmentType, GlobalStateType, MetaType, TypedAssigns}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] pub enum ContractOp<S: ContractStateAccess> { @@ -137,7 +133,7 @@ pub enum ContractOp<S: ContractStateAccess> { #[display("ldm {0},{1}")] LdM(MetaType, RegS), - /// Verify sum of pedersen commitments from inputs and outputs. + /// Verify sum of inputs and outputs are equal. /// /// The only argument specifies owned state type for the sum operation. If /// this state does not exist, or either inputs or outputs does not have @@ -145,11 +141,10 @@ pub enum ContractOp<S: ContractStateAccess> { /// /// If verification succeeds, doesn't change `st0` value; otherwise sets it /// to `false` and stops execution. - #[display("pcvs {0}")] - Pcvs(AssignmentType), + #[display("svs {0}")] + Svs(AssignmentType), - /// Verifies equivalence of a sum of pedersen commitments for the list of - /// assignment outputs to a value from `a64[0]` register. + /// Verify sum of outputs and value in `a64[0]` register are equal. /// /// The first argument specifies owned state type for the sum operation. If /// this state does not exist, or either inputs or outputs does not have @@ -159,11 +154,10 @@ pub enum ContractOp<S: ContractStateAccess> { /// /// If verification succeeds, doesn't change `st0` value; otherwise sets it /// to `false` and stops execution. - #[display("pcas {0}")] - Pcas(/** owned state type */ AssignmentType), + #[display("sas {0}")] + Sas(/** owned state type */ AssignmentType), - /// Verifies equivalence of a sum of pedersen commitments for the list of - /// inputs to a value from `a64[0]` register. + /// Verify sum of inputs and value in `a64[0]` register are equal. /// /// The first argument specifies owned state type for the sum operation. If /// this state does not exist, or either inputs or outputs does not have @@ -173,8 +167,8 @@ pub enum ContractOp<S: ContractStateAccess> { /// /// If verification succeeds, doesn't change `st0` value; otherwise sets it /// to `false` and stops execution. - #[display("pcps {0}")] - Pcps(/** owned state type */ AssignmentType), + #[display("sps {0}")] + Sps(/** owned state type */ AssignmentType), /// All other future unsupported operations, which must set `st0` to /// `false` and stop the execution. @@ -200,8 +194,8 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { | ContractOp::CnG(_, _) | ContractOp::CnC(_, _) | ContractOp::LdM(_, _) => bset![], - ContractOp::Pcvs(_) => bset![], - ContractOp::Pcas(_) | ContractOp::Pcps(_) => bset![Reg::A(RegA::A64, Reg32::Reg0)], + ContractOp::Svs(_) => bset![], + ContractOp::Sas(_) | ContractOp::Sps(_) => bset![Reg::A(RegA::A64, Reg32::Reg0)], ContractOp::Fail(_, _) => bset![], } } @@ -224,7 +218,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { | ContractOp::LdM(_, reg) => { bset![Reg::S(*reg)] } - ContractOp::Pcvs(_) | ContractOp::Pcas(_) | ContractOp::Pcps(_) => { + ContractOp::Svs(_) | ContractOp::Sas(_) | ContractOp::Sps(_) => { bset![] } ContractOp::Fail(_, _) => bset![], @@ -243,8 +237,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { | ContractOp::LdG(_, _, _) | ContractOp::LdC(_, _, _) => 8, ContractOp::LdM(_, _) => 6, - ContractOp::Pcvs(_) => 1024, - ContractOp::Pcas(_) | ContractOp::Pcps(_) => 512, + ContractOp::Svs(_) | ContractOp::Sas(_) | ContractOp::Sps(_) => 20, ContractOp::Fail(_, _) => u64::MAX, } } @@ -256,32 +249,36 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { return ExecStep::Stop; }}; } - macro_rules! load_inputs { + macro_rules! load_revealed_inputs { ($state_type:ident) => {{ let Some(prev_state) = context.op_info.prev_state.get($state_type) else { fail!() }; match prev_state { - TypedAssigns::Fungible(state) => state - .iter() - .map(Assign::to_confidential_state) - .map(|s| s.commitment.into_inner()) - .collect::<Vec<_>>(), + TypedAssigns::Fungible(state) => { + let mut values = vec![]; + for assign in state.iter().map(Assign::as_revealed_state) { + values.push(assign.value.as_u64()) + } + values + } _ => fail!(), } }}; } - macro_rules! load_outputs { + macro_rules! load_revealed_outputs { ($state_type:ident) => {{ let Some(new_state) = context.op_info.owned_state.get(*$state_type) else { fail!() }; match new_state { - TypedAssigns::Fungible(state) => state - .iter() - .map(Assign::to_confidential_state) - .map(|s| s.commitment.into_inner()) - .collect::<Vec<_>>(), + TypedAssigns::Fungible(state) => { + let mut values = vec![]; + for assign in state.iter().map(Assign::as_revealed_state) { + values.push(assign.value.as_u64()) + } + values + } _ => fail!(), } }}; @@ -339,12 +336,8 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { else { fail!() }; - let state = state.map(|s| s.value.as_inner()); - if let Some(state) = state { - regs.set_s16(*reg, state); - } else { - regs.clr_s16(*reg); - } + let state = state.value.as_inner(); + regs.set_s16(*reg, state); } ContractOp::LdS(state_type, reg_32, reg) => { let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { @@ -360,12 +353,8 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { else { fail!() }; - let state = state.map(|s| s.value.into_inner()); - if let Some(state) = state { - regs.set_s16(*reg, state); - } else { - regs.clr_s16(*reg); - } + let state = state.value.into_inner(); + regs.set_s16(*reg, state); } ContractOp::LdF(state_type, reg_32, reg) => { let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { @@ -381,7 +370,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { else { fail!() }; - regs.set_n(RegA::A64, *reg, state.map(|s| s.value.as_u64())); + regs.set_n(RegA::A64, *reg, state.value.as_u64()); } ContractOp::LdG(state_type, reg_8, reg_s) => { let Some(reg_32) = *regs.get_n(RegA::A8, *reg_8) else { @@ -423,61 +412,54 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> { }; regs.set_s16(*reg, meta.to_inner()); } - - ContractOp::Pcvs(state_type) => { - let inputs = load_inputs!(state_type); - let outputs = load_outputs!(state_type); - if !secp256k1_zkp::verify_commitments_sum_to_equal( - secp256k1_zkp::SECP256K1, - &inputs, - &outputs, - ) { + ContractOp::Svs(state_type) => { + let Some(input_amt) = load_revealed_inputs!(state_type) + .iter() + .try_fold(0u64, |acc, &x| acc.checked_add(x)) + else { + fail!() + }; + let Some(output_amt) = load_revealed_outputs!(state_type) + .iter() + .try_fold(0u64, |acc, &x| acc.checked_add(x)) + else { + fail!() + }; + if input_amt != output_amt { fail!() } } - - ContractOp::Pcas(owned_state) => { + ContractOp::Sas(owned_state) => { let Some(sum) = *regs.get_n(RegA::A64, Reg32::Reg0) else { fail!() }; let sum = u64::from(sum); - let Some(tag) = context.asset_tags.get(owned_state) else { + let Some(output_amt) = load_revealed_outputs!(owned_state) + .iter() + .try_fold(0u64, |acc, &x| acc.checked_add(x)) + else { fail!() }; - let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); - let inputs = [PedersenCommitment::commit(&sum).into_inner()]; - let outputs = load_outputs!(owned_state); - - if !secp256k1_zkp::verify_commitments_sum_to_equal( - secp256k1_zkp::SECP256K1, - &inputs, - &outputs, - ) { + if sum != output_amt { fail!() } } - - ContractOp::Pcps(owned_state) => { + ContractOp::Sps(owned_state) => { let Some(sum) = *regs.get_n(RegA::A64, Reg32::Reg0) else { fail!() }; let sum = u64::from(sum); - let Some(tag) = context.asset_tags.get(owned_state) else { + let Some(input_amt) = load_revealed_inputs!(owned_state) + .iter() + .try_fold(0u64, |acc, &x| acc.checked_add(x)) + else { fail!() }; - let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); - - let inputs = [PedersenCommitment::commit(&sum).into_inner()]; - let outputs = load_inputs!(owned_state); - if !secp256k1_zkp::verify_commitments_sum_to_equal( - secp256k1_zkp::SECP256K1, - &inputs, - &outputs, - ) { + if sum != input_amt { fail!() } } @@ -505,9 +487,9 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> { ContractOp::LdC(_, _, _) => INSTR_LDC, ContractOp::LdM(_, _) => INSTR_LDM, - ContractOp::Pcvs(_) => INSTR_PCVS, - ContractOp::Pcas(_) => INSTR_PCAS, - ContractOp::Pcps(_) => INSTR_PCPS, + ContractOp::Svs(_) => INSTR_SVS, + ContractOp::Sas(_) => INSTR_SAS, + ContractOp::Sps(_) => INSTR_SPS, ContractOp::Fail(other, _) => *other, } @@ -567,9 +549,9 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> { writer.write_u4(u4::ZERO)?; } - ContractOp::Pcvs(state_type) => writer.write_u16(*state_type)?, - ContractOp::Pcas(owned_type) => writer.write_u16(*owned_type)?, - ContractOp::Pcps(owned_type) => writer.write_u16(*owned_type)?, + ContractOp::Svs(state_type) => writer.write_u16(*state_type)?, + ContractOp::Sas(owned_type) => writer.write_u16(*owned_type)?, + ContractOp::Sps(owned_type) => writer.write_u16(*owned_type)?, ContractOp::Fail(_, _) => {} } @@ -634,9 +616,9 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> { i } - INSTR_PCVS => Self::Pcvs(reader.read_u16()?.into()), - INSTR_PCAS => Self::Pcas(reader.read_u16()?.into()), - INSTR_PCPS => Self::Pcps(reader.read_u16()?.into()), + INSTR_SVS => Self::Svs(reader.read_u16()?.into()), + INSTR_SAS => Self::Sas(reader.read_u16()?.into()), + INSTR_SPS => Self::Sps(reader.read_u16()?.into()), x => Self::Fail(x, PhantomData), }) @@ -658,7 +640,7 @@ mod test { #[test] fn encoding() { let code = - [Instr::ExtensionCodes(RgbIsa::Contract(ContractOp::Pcvs(AssignmentType::from(4000))))]; + [Instr::ExtensionCodes(RgbIsa::Contract(ContractOp::Svs(AssignmentType::from(4000))))]; let alu_lib = Lib::assemble(&code).unwrap(); eprintln!("{alu_lib}"); let alu_id = alu_lib.id(); diff --git a/src/vm/opcodes.rs b/src/vm/opcodes.rs index b1db3ea4..e14d370a 100644 --- a/src/vm/opcodes.rs +++ b/src/vm/opcodes.rs @@ -43,9 +43,9 @@ pub const INSTR_LDC: u8 = 0b11_001_001; pub const INSTR_LDM: u8 = 0b11_001_010; // Reserved 0b11_001_111 -pub const INSTR_PCVS: u8 = 0b11_010_000; -pub const INSTR_PCAS: u8 = 0b11_010_001; -pub const INSTR_PCPS: u8 = 0b11_010_010; +pub const INSTR_SVS: u8 = 0b11_010_000; +pub const INSTR_SAS: u8 = 0b11_010_001; +pub const INSTR_SPS: u8 = 0b11_010_010; // Reserved 0b11_010_011 pub const INSTR_CONTRACT_FROM: u8 = 0b11_000_000; pub const INSTR_CONTRACT_TO: u8 = 0b11_010_011; diff --git a/stl/AnchoredBundle.vesper b/stl/AnchoredBundle.vesper index 70188880..6f3ea5a3 100644 --- a/stl/AnchoredBundle.vesper +++ b/stl/AnchoredBundle.vesper @@ -8,7 +8,6 @@ Bundles vesper lexicon=types+commitments BundleId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:bundle#2024-02-03 - Method serialized InputMap serialized DbcProof union @@ -20,7 +19,6 @@ DbcProof union opret is Unit wrapped aka=OpretProof tag=1 TransitionBundle rec - closeMethod enum Method opretFirst=0 tapretFirst=1 inputMap map len=1..MAX16 aka=InputMap key is U32 aka=Vout value bytes len=32 aka=OpId @@ -51,165 +49,97 @@ TransitionBundle rec declarative list len=0..MAX16 wrapped tag=0 AssignVoidStateBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 fungible list len=0..MAX16 wrapped tag=1 AssignRevealedValueBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment + value union FungibleState + bits64 is U64 wrapped tag=0 + concealedDummy is Unit lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment + value union FungibleState + bits64 is U64 wrapped tag=0 + concealedDummy is Unit lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec RevealedFungible value union FungibleState bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec RevealedFungible value union FungibleState bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag lock bytes len=2 aka=ReservedBytes2 structured list len=0..MAX16 wrapped tag=2 AssignRevealedDataBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state bytes len=32 aka=ConcealedData lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state bytes len=32 aka=ConcealedData lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec RevealedData value bytes len=0..MAX16 aka=DataState salt is U128 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec RevealedData value bytes len=0..MAX16 aka=DataState salt is U128 @@ -217,33 +147,20 @@ TransitionBundle rec attachment list len=0..MAX16 wrapped tag=3 AssignRevealedAttachBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state bytes len=32 aka=ConcealedAttach lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state bytes len=32 aka=ConcealedAttach lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec RevealedAttach file rec AttachState id bytes len=32 aka=AttachId @@ -251,21 +168,12 @@ TransitionBundle rec salt is U64 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec RevealedAttach file rec AttachState id bytes len=32 aka=AttachId diff --git a/stl/RGBCommit@0.1.0.sta b/stl/RGBCommit@0.1.0.sta index 67979284..ced2066b 100644 --- a/stl/RGBCommit@0.1.0.sta +++ b/stl/RGBCommit@0.1.0.sta @@ -1,270 +1,265 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:IFcnrPeI-TANxLfZ-feJax6Q-1TUM4Hq-AjI161s-3tbmxak#harvest-person-orion +Id: stl:n4BoS9Kd-oZ1mUgb-6Hqg9hY-q$JXa84-YoWed1a-!6AZCTM#raymond-open-organic Name: RGBCommit Dependencies: + BPCore#symbol-tropic-grand, StrictTypes#century-comrade-chess, - BPCore#austin-story-retro, AluVM#congo-archive-folio, CommitVerify#miller-pancake-elastic, Std#ralph-blue-lucky, Bitcoin#signal-color-cipher -Check-SHA256: 1d68b2a0bcfecf99effcecd7c9c35f870a1300e71a3ce3da8144587537895235 +Check-SHA256: 88954d8b1822bdd4fb13a2f1eb7fc7eec49e010e69dcbd009e07aff60255070a -2~tNwLvL+uX><lf>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI)Q*?4^V{}w`aAk8=6V}(%hjW>8 -uUwNXi!t*yd7K}=K!`A`1OPgv%fUznLQq3*a%Ez0HGd)H<Dj;Nz^!EbXX{KgjJY{tu+xnhvc`|O#x?~( +2~tNwLvL+uX><l5aI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP{iLQq3*a%Dy8qhH(h<B$P5@#5`< +3V$8+S7~5Qj4-A{WE1=O5ZMb;baH89bX0k8WpiS1HGd)H<Dj;Nz^!EbXX{KgjJY{tu+xnhvc`|O#x?~( Y;{&mdIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#3`1{iZE18?WpZg|dCDvvZ-bfLFbqC#o>4E? M+l67UG^w8*<_XZ#%uyqCj(P-Wc6$lVk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3I{@IbYpL6ZUzNG Y;{&m0sw9Ap(f$Hb>aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++hbyX<}1pbY-V7RRS&fT*&Z=qeY@Wmfle* -z!SF)@h8|JkU^FEQwjx4X<|ua20~CnZ*pY?04}!>CAn^87TS9h9ibhaZ&^Bcn*B*;w|~I;-PD|t>jq6_ -bZBp6MklB)P_)|`Y=H7dO_e!^G2i>0SdC0NppV!6v|_i_4nk~cZe&wsVQf@*P;_!=8SA{&vly$FvzVnz -Hf7z~rv`86=_Ka^V5yX|y#`JSQ)OdvWpq<zVQjF*aju4Y+v8xG!`|yM#YZ<B0M5p`QE^diRnUc7&+83B -Y-w&}Q)OXnRCsA*vE?{96bd-L@NXK=z8qksZ{gweeRv2cdB4&6(-0xu1yp!YbaDqmX>?<6X>I}lA>%$n -#j0HLDJN5-IKgM_J7b(p+0MPGk2Gl)y2(Rz1Xgc#bfbbo^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1 -Rs>XdX=DsTZ*6U9bXH|@X=Zr^063mQh9?yTI7S;;e;>sZfv!yd427@;7veO2zMB=|GYU;*a%*g5NMUnm -ZLh7x^`{^P$fKg#%8c8X#<$(NgM!uni2C|Kr}onZ3R84)X=8LqVRLAc_h5K%L=laq&yA1JoJ^{7>oKLk -F4~iax8KK|47hp@Qe|^xa&~28LV0v$b1}=fEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RawDWpib6 -c4cHjd30rSGX8=VN#A(BKKz&v`r;e6DUv<<*U}c<e%g}v1+@9m9u87vb7gXNWn@BmbY*im15<Ql1OQ0B -BNr;@ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbeZ<b7N^~P;zN*bYWs_WnqRQ(R;4&W&+>mb;*F>vukd; -=m`ygb@x#_>`RmOO$0)3Z)}yry~#}iVEJ)s5j^%uEnQ9{n2s|9Fa^ps+HG#`XS5DMY;b5{PIYZeZ)9O} -Xt{%a=RmHK6WZ%EWRm@*ULd%lgGoFTxU<Z3$DN1yuMa_NaA;veVQ_OyZ)9O}XbV$xa%p39RC#b^a{>TU -76^nC$%1sKzB<;EQA|)S-x88IWKN#S$#@T&w`gPtRC#b^PGN0jYXqYdo~D%m7H6OD0<^0n_2##VWXRdj -y=DB@qgYOj1yf~hNn}O<2|;XhOksItaxnt|25f0@b!lV)3_)ykOksItaxqh7bOiwb2?5A!f_n>Eea4Xl -By!~<Cy&t2#Tr*=pi4ihF+dwUej@+?000000093000000000O<b8}^MRAFZY0RRU806-uB2|;snWpq?w -XLAJs015$z{^Dg=h-~N_zJ`Red1EINWrM}GXaQb}6c#qIM2EQn$&Z?;!v;$l{rzVfm%J+c{!D0(A9Khp ->v3=AX`3Ri0000000000{{R3000000B0+O=X=iRyWp-s@Y-MCYbaY{3XhLjhZe&wsVQf@*P;_zx1ON<U -Z*FF3WMyu2X<=*t1_K0hWnpXq+lpEmf)o&SDDwD>KtpQ8M_qJyiO1VIUJ=H=)@ii_1#@&^bY%hjG)3KC -&kYOztQDksx&<QOTZ=0jFlADQgO7VH>yAAHY;R+00(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@O -Cd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0Ra(XZ*FF3WMyu2X<=+rbYXO500sjDb7f&{0gt=F -=tr7P<W1sTaeuw~6S&mTk+f}*!2lu#8{vv^H3f5YVRU5y{4_<~U(XE-|Ev|Hdb$N7;9H9;8!%;3hl7uM -E$faw1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n --dr?jcD1Ll0RaLKV{dL|X=G(?bZKF1Q)OXn00sjDb7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaR -zSe2A1O;<+VRU5y=Ov5&mq(eSq^TM>JW4?*h+3X!X@fjr@d0IimUQ-Q1Z;0(YXW)$9p7nv%krpqN<S4B -4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaODa%Fa9VQgh&00sjD -b7f&{0gt=F=tr7P<W1sTaeuw~6S&mTk+f}*!2lu#8{vv^H3f5YVRU5y=Ov5&mq(eSq^TM>JW4?*h+3X! -X@fjr@d0IimUQ-Q1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn -@L3mU0Z2&n-dr?jcD1Ll0RbUFb8~5DZc=4-WnpY(WI=RvVPj}QY-w&}Q)OXnRCsA*1OxyKV{dL|X=G(? -bZKF100sjDb7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5y{4_<~U(XE-|Ev|H -db$N7;9H9;8!%;3hl7uME$faw1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D -^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaIKV{dL|X=G(?bZKF1Q*>c;WdH^P1aoC!YypA{4X<ncGy!)g -sJ>Egn0epQk*PX+nL>xOm%pK>soMo}bYXO50sJ&Y-CxfQ3;(PYq<XpqBH&w#D;qFnQip?&doAmZJp^oT -V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)y -umJ%A5Mys{W@%()Zggp3Y*S@nYybuW1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuo -bYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWFewK9hZ3Jv@V`~C>10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypA{ -4X<ncGy!)gsJ>Egn0epQk*PX+nL>xOm%pK>soMo}bYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWF -ewK9hZ3Jv@V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^ -^xj-FXm+)yumJ%eL349yXKqquc4c8~Wn@HQbYVhlX>MdwWnpYocu;h51OxyKV{dL|X=G(?bZKF100sjD -b7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5ya1CV;vVwtcAGbZ_5@VACR|ut2 -VXXq-)V^B9&!_4M1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn -@L3mU0Z2&n-dr?jcD1Ll0RaIKV{dL|X=G(?bZKF1Q*>c;WdH^P1aoC!YypqE!sthuPUKDEU2%WC`V+X+ -(UG)mk--2W1{>juaWw^VbYXO50dNgv5VC@SZy&ck<q~6)16K&8QemwE;MBfa#m}ee2?T6!V`~C>10COK -earHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{ -W@%()Zggp3Y*S@nYybuW1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50sm-Y -z<5%CY59k^g5#W{6D&GDo53%OaP0&iRq<soUj%G#V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC -#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypqE!sthuPUKDE -U2%WC`V+X+(UG)mk--2W1{>juaWw^VbYXO50sm-Yz<5%CY59k^g5#W{6D&GDo53%OaP0&iRq<soUj%G# -V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)y -umJ%dL349yXKqquc4c8~Wn@HQbYVhlX>MdwWnpYocxhw=1ON<UZ*FF3WMyu2X<=*t1_K0hWnpXq+lpEm -f)o&SDDwD>KtpQ8M_qJyiO1VIUJ=H=)@ii_1#@&^bY%f>4P_9rf`M-zw>{+&W0M0{2&GbCtpecGzFNi4 -r|Jm=Y;R+00(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YF -Tr_BQwWqKF0Ra(XZ*FF3WMyu2X<=+rbYXO500sjDb7f&{0fGz-uWS7@0e2{<zEW_QdEe5JsXBX^LWi`M -zoDn8+XZuUVRU5ya1CV;vVwtcAGbZ_5@VACR|ut2VXXq-)V^B9&!_4M1Z;0(YXW)$9p7nv%krpqN<S4B -4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaLKV{dL|X=G(?bZKF1 -Q)OXn00sjDb7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5y|7c^tcv66A`G>fI -<D8=tEIK}$!7qz&?F1iH@ntYy1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D -^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaODa%Fa9VQgh&00sjDb7f&{0fGz-uWS7@0e2{<zEW_QdEe5J -sXBX^LWi`MzoDn8+XZuUVRU5y|7c^tcv66A`G>fI<D8=tEIK}$!7qz&?F1iH@ntYy1Z;0(YXW)$9p7nv -%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RbUFb8~5D -Zc=4-WnpY(WL9Bpb!9?qX>MdwWnpYocu;h51OxyKV{dL|X=G(?bZKF100sjDb7f&{0o#gN8iEuMbtv-q -j6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5yN@#iqkT|?l*=bx{^0c**fmF&H)l(b`S3$sb4!MK-1Z;0( -YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll -0RaIKV{dL|X=G(?bZKF1Q*>c;WdH^P1aoC!YypqE!sthuPUKDEU2%WC`V+X+(UG)mk--2W1{>juaWw^V -bYXO50ZM3k2aq_tRM}}<T=KNFl7Upp8`V=B3s*tFb`H6N`vh!nV`~C>10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@nYybuW -1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50c}La^e<`!Iztr?rsl#d#OQkE -ER^^L)C{HEhxT=ipag7hV`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_ -sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypqE!sthuPUKDEU2%WC`V+X+(UG)mk--2W -1{>juaWw^VbYXO50c}La^e<`!Iztr?rsl#d#OQkEER^^L)C{HEhxT=ipag7hV`~C>10COKearHwcS=7M -7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%eL349yXKqquc4c8~ -Wn@-iY;|QqY-w&}Q)OXnRCsA*1OxyKV{dL|X=G(?bZKF100sjDb7f&{0o#gN8iEuMbtv-qj6g$b#7A9p -c!|f`I$jaRzSe2A1O;<+VRU5yN@#iqkT|?l*=bx{^0c**fmF&H)l(b`S3$sb4!MK-1Z;0(YXW)$9p7nv -%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaIKV{dL| -X=G(?bZKF1Q*>c;WdH^P1aoC!YypA{4X<ncGy!)gsJ>Egn0epQk*PX+nL>xOm%pK>soMo}bYXO50ZM3k -2aq_tRM}}<T=KNFl7Upp8`V=B3s*tFb`H6N`vh!nV`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC -#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@nYybuW1aoC!YysPf -S{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50c}La^e<`!Iztr?rsl#d#OQkEER^^L)C{HE -hxT=ipag7hV`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^ -^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypA{4X<ncGy!)gsJ>Egn0epQk*PX+nL>xOm%pK>soMo} -bYXO50c}La^e<`!Iztr?rsl#d#OQkEER^^L)C{HEhxT=ipag7hV`~C>10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%bL349yXKq$+X=GD$VRU6eY-w&} -Q)OXnRCrKyas&hb3}bI@W@%()Zggp3YybuW1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2R -wFCuobYXO50WPwo{ujV7L@=1(T$>wOY}Ov_b`4?P%YY`+Wb+o`y98`+V`~C>10COKearHwcS=7M7YzYa +z!SF)@h8|JkU^FEQwjx4X<|ua20~CnZ*pY>04xKINJ~fc1UzTDb_LBRjrSXj?;k=^zm6d~Uh7!wPz^$C +X>MdwWnpYocxhy48SA{&vly$FvzVnzHf7z~rv`86=_Ka^V5yX|y#`JSQ)OdvWpq<zVQi<U^0@;NPlb{- +n1xko1uZcKL=FhMw)iW@^B~GyS4Iv(Y-w&}Q)OXnRCrKya<Sz&ITQ*wzVL4v&%PXBrElTk^nG{;D0#op +`qL00-33&5P;_z!LTPkkZ)t7<03qW(L&d6G@+l`%qd385?K@+fP1(-9sgE>i7rMzqbp%##b#$YGLi5Yl +(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW`Kcxhw|LvL+uX>?X)a%pCH1pqjnLxv|61vo|<S$`kJ6oIZx +{|tq&1{dNqe!iO(;xh_OWpZn5Wk_LjXl<{p#r3Bk2FRnL+RBXEn8vr=x`Tq%|A_kfK&ST81`1Pja%p39 +NMUnmllNeFa6}P}rq7L!(40)FbL%msz%JU8hqvFyoea2o4pL=vWpZ|9WI}m#WpgphxGg*8X!CPrawgw_ +sqk4BX8}k^^xj-FXm+)yumJ%MQe|^xa&~28LV0v$b29#d7D?ZDzCQez5c=X9w<(f6`q$DH-G17V_XV{1 +(H;&`Wpib6c4cHjd30rSI0I93WCH+5z9SbZ=!8X@=Yuq$20sb<4l#S`iz7Vef}@Ca=a#q*L33kiX;5-$ +ZggQ{Y-N?hy~#}iVEJ)s5j^%uEnQ9{n2s|9Fa^ps+HG#`XS5DMY;b5{PIYZeZ)9O}Xt{%a=RmHK6WZ%E +WRm@*ULd%lgGoFTxU<Z3$DN1yuMa_NaA;veVQ_OyZ)9O}XbV$xa%p39RC#b^a{>TU76^nC$%1sKzB<;E +QA|)S-x88IWKN#S$#@T&w`gPtRC#b^PGN0jYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj1yf~h +Nn||$B0+O=X=iRyWp-s@Y-MCYbaY{3XhLjhZe&wsVQf@*P;_zx1ON<UZ*FF3WMyu2X<=*t1_K0hWnpXr +A#kgq^`I&ZzC?)!&R01Y?(H9FO$CR6P1%k7c67A-Xc_Cg)w39@m$R6qOEzWQ+NTC@=;<Wq17N9?v%LmR +1#@&^bY%hjG)3KC&kYOztQDksx&<QOTZ=0jFlADQgO7VH>yAAHY;R+00(t`--)Viz@~C%8KNS}Z0aQ3s +^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0Ra(XZ*FF3WMyu2X<=+rbYXO5 +00sjDb7f&{0wHj#q4l6D4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{HLh$xdReUg_1Rxg;i+<Einc}4hXxp +_$$ZrAj(}=Mg?<pVRU5y{4_<~U(XE-|Ev|Hdb$N7;9H9;8!%;3hl7uME$faw1Z;0(YXW)$9p7nv%krpq +N<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaLKV{dL|X=G(? +bZKF1Q)OXn00sjDb7f&{0wHj#q4l6D4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{Ad~Lyw$T9tCzEwrAszt +-P)%HZ|LbH=L2A=l(W4CP6cyxVRU5y=Ov5&mq(eSq^TM>JW4?*h+3X!X@fjr@d0IimUQ-Q1Z;0(YXW)$ +9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaOD +a%Fa9VQgh&00sjDb7f&{0wHj#q4l6D4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{HLh$xdReUg_1Rxg;i+< +Einc}4hXxp_$$ZrAj(}=Mg?<pVRU5y=Ov5&mq(eSq^TM>JW4?*h+3X!X@fjr@d0IimUQ-Q1Z;0(YXW)$ +9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RbUF +b8~5DZc=4-WnpY(WI=RvVPj}QY-w&}Q)OXnRCsA*1OxyKV{dL|X=G(?bZKF100sjDb7f&{0wHj#q4l6D +4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{Ad~Lyw$T9tCzEwrAszt-P)%HZ|LbH=L2A=l(W4CP6cyxVRU5y +{4_<~U(XE-|Ev|Hdb$N7;9H9;8!%;3hl7uME$faw1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ- +4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaIKV{dL|X=G(?bZKF1Q*>c;WdH^P1aoC! +Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwEQdsjYvyJ^#nX;x^@N4Cyn<TjPD;pQooKNI$rBo +>`(=BbYXO50sJ&Y-CxfQ3;(PYq<XpqBH&w#D;qFnQip?&doAmZJp^oTV`~C>10COKearHwcS=7M7YzYa +I8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@n +YybuW1aoC!Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwESop>%7&o7^|1Fn59cLW!>7R25;!; +B<BNQsg$$522KTYbYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWFewK9hZ3Jv@V`~C>10COKearHw +cS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY( +WB>*O1aoC!Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwEQdsjYvyJ^#nX;x^@N4Cyn<TjPD;p +QooKNI$rBo>`(=BbYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWFewK9hZ3Jv@V`~C>10COKearHw +cS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%eL349yXKqqu +c4c8~Wn@HQbYVhlX>MdwWnpYocu;h51OxyKV{dL|X=G(?bZKF100sjDb7f&{0wHj#q4l6D4ZcK)2hLYH +81C&KXiWu&flb+s{C0G-{Ad~Lyw$T9tCzEwrAszt-P)%HZ|LbH=L2A=l(W4CP6cyxVRU5ya1CV;vVwtc +AGbZ_5@VACR|ut2VXXq-)V^B9&!_4M1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNf +Ej#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaIKV{dL|X=G(?bZKF1Q*>c;WdH^P1aoC!Yyu&0tD*Iv +Dh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwEU;2^0@;NPlb{-n1xko1uZcKL=FhMw)iW@^B~GyS4IVMbYXO5 +0dNgv5VC@SZy&ck<q~6)16K&8QemwE;MBfa#m}ee2?T6!V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc? +)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@nYybuW1aoC! +Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwESop>%7&o7^|1Fn59cLW!>7R25;!;B<BNQsg$$5 +22KTYbYXO50sm-Yz<5%CY59k^g5#W{6D&GDo53%OaP0&iRq<soUj%G#V`~C>10COKearHwcS=7M7YzYa +I8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC! +Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwEU;2^0@;NPlb{-n1xko1uZcKL=FhMw)iW@^B~Gy +S4IVMbYXO50sm-Yz<5%CY59k^g5#W{6D&GDo53%OaP0&iRq<soUj%G#V`~C>10COKearHwcS=7M7YzYa +I8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%dL349yXKqquc4c8~Wn@HQ +bYVhlX>MdwWnpYocxhw=1ON<UZ*FF3WMyu2X<=*t1_K0hWnpXrA#kgq^`I&ZzC?)!&R01Y?(H9FO$CR6 +P1%k7c67A-Xc_Cg)w39@m$R6qOEzWQ+NTC@=;<Wq17N9?v%LmR1#@&^bY%f>4P_9rf`M-zw>{+&W0M0{ +2&GbCtpecGzFNi4r|Jm=Y;R+00(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS +-+`&{Sr=ykNJ#YFTr_BQwWqKF0Ra(XZ*FF3WMyu2X<=+rbYXO500sjDb7f&{0wHj#q4l6D4ZcK)2hLYH +81C&KXiWu&flb+s{C0G-{44{FNJ~fc1UzTDb_LBRjrSXj?;k=^zm6d~Uh7!wPz7^zVRU5ya1CV;vVwtc +AGbZ_5@VACR|ut2VXXq-)V^B9&!_4M1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNf +Ej#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaLKV{dL|X=G(?bZKF1Q)OXn00sjDb7f&{0wHj#q4l6D +4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{Ad~Lyw$T9tCzEwrAszt-P)%HZ|LbH=L2A=l(W4CP6cyxVRU5y +|7c^tcv66A`G>fI<D8=tEIK}$!7qz&?F1iH@ntYy1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ- +4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaODa%Fa9VQgh&00sjDb7f&{0wHj#q4l6D +4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{44{FNJ~fc1UzTDb_LBRjrSXj?;k=^zm6d~Uh7!wPz7^zVRU5y +|7c^tcv66A`G>fI<D8=tEIK}$!7qz&?F1iH@ntYy1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ- +4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RbUFb8~5DZc=4-WnpY(WL9Bpb!9?qX>Mdw +WnpYocu;h51OxyKV{dL|X=G(?bZKF100sjDb7f&{0wHj#q4l6D4ZcK)2hLYH81C&KXiWu&flb+s{C0G- +{Ad~Lyw$T9tCzEwrAszt-P)%HZ|LbH=L2A=l(W4CP6cyxVRU5ypQhuJ<OPr`%Q+!jd;X?okwlk%KLRn3 +&tf_NdFbY21Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU +0Z2&n-dr?jcD1Ll0RaIKV{dL|X=G(?bZKF1Q*>c;WdH^P1aoC!Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vl +hk;Gmjr?|WwEU;2^0@;NPlb{-n1xko1uZcKL=FhMw)iW@^B~GyS4IVMbYXO50iUMhljH@EE6X_{Tzmee +W|2gfem?>+kk4W|0D0)<V+3q(V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPr +awgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@nYybuW1aoC!Yyu&0tD*IvDh<9wi3iSC +IT-HkA81Vlhk;Gmjr?|WwESop>%7&o7^|1Fn59cLW!>7R25;!;B<BNQsg$$522KTYbYXO50W~^?7W_p; +3l@ykBm9id47>4{Q314kUM@UiqyMDEzyxe>V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFs +xGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!Yyu&0tD*IvDh<9wi3iSC +IT-HkA81Vlhk;Gmjr?|WwEU;2^0@;NPlb{-n1xko1uZcKL=FhMw)iW@^B~GyS4IVMbYXO50W~^?7W_p; +3l@ykBm9id47>4{Q314kUM@UiqyMDEzyxe>V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFs +xGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%eL349yXKqquc4c8~Wn@-iY;|QqY-w&}Q)OXnRCsA* +1OxyKV{dL|X=G(?bZKF100sjDb7f&{0wHj#q4l6D4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{Ad~Lyw$T9 +tCzEwrAszt-P)%HZ|LbH=L2A=l(W4CP6cyxVRU5ypQhuJ<OPr`%Q+!jd;X?okwlk%KLRn3&tf_NdFbY2 +1Z;0(YXW)$9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<aNfEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?j +cD1Ll0RaIKV{dL|X=G(?bZKF1Q*>c;WdH^P1aoC!Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|W +wEQdsjYvyJ^#nX;x^@N4Cyn<TjPD;pQooKNI$rBo>`(=BbYXO50iUMhljH@EE6X_{TzmeeW|2gfem?>+ +kk4W|0D0)<V+3q(V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4B +X8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@nYybuW1aoC!Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vl +hk;Gmjr?|WwESop>%7&o7^|1Fn59cLW!>7R25;!;B<BNQsg$$522KTYbYXO50W~^?7W_p;3l@ykBm9id +47>4{Q314kUM@UiqyMDEzyxe>V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPr +awgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vl +hk;Gmjr?|WwEQdsjYvyJ^#nX;x^@N4Cyn<TjPD;pQooKNI$rBo>`(=BbYXO50W~^?7W_p;3l@ykBm9id +47>4{Q314kUM@UiqyMDEzyxe>V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPr +awgw_sqk4BX8}k^^xj-FXm+)yumJ%bL349yXKq$+X=GD$VRU6eY-w&}Q)OXnRCrKyas&hb3}bI@W@%() +Zggp3YybuW1aoC!Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwESop>%7&o7^|1Fn59cLW!>7R +25;!;B<BNQsg$$522KTYbYXO50WPwo{ujV7L@=1(T$>wOY}Ov_b`4?P%YY`+Wb+o`y98`+V`~C>10COK +earHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%95o2#| +W@%()Zggp3Y*Tb$bY%br0|awrVQc~+aI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP}ZsPef35>JJa +HJF7}X$37Y21E`BySDf%$MYb{T~|g0b97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{(`54&;kyKE +Z)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%TNc7%ZG-!6U +r?3G50uW<wZf0p@Wo~q7VQf=nVQc^f0|awrVQc~+aI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP|v +8SA{&vly$FvzVnzHf7z~rv`86=_Ka^V5yX|y#`JNb97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{ +(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%T +Nc7%ZG-!6Ur?3G50|;_uc4c8~Wn=&b0|awrVQc~+aI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP}Z +sPef35>JJaHJF7}X$37Y21E`BySDf%$MYb{T~|g0b97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{ +(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%T +Nc7%ZG-!6Ur?3G596@t)X=iR$Z)s#xbYXO5LTqVnWK(5fY*ct@WCR2N3}bI@W@%()Zggp3YybuW1aoC! +Yyu&0tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwESop>%7&o7^|1Fn59cLW!>7R25;!;B<BNQsg$$5 +22KTYbYXO50WPwo{ujV7L@=1(T$>wOY}Ov_b`4?P%YY`+Wb+o`y98`+V`~C>10COKearHwcS=7M7YzYa I8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%95o2#|W@%()Zggp3Y*Tb$ -bY%br0|awrVQc}9yTa&4noi_R;$3lnz4{Zl)X|Z&ZIQtMA_g1big7gsb97;JWdSa-rT!PdFhnqz;9Q#< -T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVC -WpXCpfvNCW7iR%TNc7%ZG-!6Ur?3G50uW<wZf0p@Wo~q7VQf=nVQc^f0|awrVQc~0idq_i6cBYN^7xEE -Lu$lFU37Sf$J;ty5yrmOX|)6eb97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$ +bY%br0|awrVQc~+aI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP{|1C2;aNA(0eXS#L;%_oib8;tKC +LQ=nuAv#{`SnN;*b97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$dIKHbX?@G` +sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%TNc7%ZG-!6Ur?3G50uW<wZf0p@ +Wo~q7VQf=nVQc^f0|awrVQc~+aI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP|v8SA{&vly$FvzVnz +Hf7z~rv`86=_Ka^V5yX|y#`JNb97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$ dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%TNc7%ZG-!6Ur?3G5 -0|;_uc4c8~Wn=&b0|awrVQc}9yTa&4noi_R;$3lnz4{Zl)X|Z&ZIQtMA_g1big7gsb97;JWdSa-rT!Pd -Fhnqz;9Q#<T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<# -%eXB&=4kVCWpXCpfvNCW7iR%TNc7%ZG-!6Ur?3G596@t)X=iR$Z)s#xbYXO5LTqVnWK(5fY*ct@WCR2N -3}bI@W@%()Zggp3YybuW1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50WPwo -{ujV7L@=1(T$>wOY}Ov_b`4?P%YY`+Wb+o`y98`+V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC -#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%95o2#|W@%()Zggp3Y*Tb$bY%br0|awrVQc|{ -3=OYq{WJl0D5$<taF}`D(vhh;dznIqw3ol3r>WZob97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{ -(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%T -Nc7%ZG-!6Ur?3G50uW<wZf0p@Wo~q7VQf=nVQc^f0|awrVQc~0idq_i6cBYN^7xEELu$lFU37Sf$J;ty -5yrmOX|)6eb97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~ -6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%TNc7%ZG-!6Ur?3G50|;_uc4c8~Wn=&b -0|awrVQc|{3=OYq{WJl0D5$<taF}`D(vhh;dznIqw3ol3r>WZob97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H -?RE`e-pha{(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCp -fvNCW7iR%TNc7%ZG-!6Ur?3G54ncEsX=iS2Wo~p-d2nR~0RR9389{S%X=iS2Wo~qHLTqVnWK(5fY*ctq -baDj&015$z{^Dg=h-~N_zJ`Red1EINWrM}GXaQb}6c#qIM2EQnd$KicKz74!90ND1i-DNy><~nFGwl#> -J&iiT&+eT*0000000000{{R30000007(sJ$X=iS2Wo~qHLTqVnWK(5fY*ct@WCZ~L3IT`y;$>KfZ0H=m -hJ>?uV<!`3gT=OJ0bYv~7B;a&hq(b-Z)vk7zTZV$_{ZYwZsV-}v4k`%cR+ywTd+-_+35lR0000000030 -0000000008L3DIsV`xca1pxpD002NB01H8MbYWv?Q*>c;Wd;HQX=DL}aSf9!PV~dK2uo>;u!nFdemP_$ -e?^hl+JkM;eY!XaZDnL>VN`i=WdTAkVTFju)T<OGK*#;b7c9-t{}BHTlYjt3e2ALe%y|w%VRL0eZ*6U9 -bZupBbOr|nW^7?+a{_t;9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<YPmV0dsu5sjwLjgQcrOsaG1 -F{QvR+LMR3-^ZN{xOxb4V`yb<VM$~Glv2~%1FNg3QJ<&wKF}2F)J=UcKm7gx`duV?R0NO^33O>~Wpi|4 -ZEyepNCs(hb9H5M0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr= -x`Tq%|A_kfK&ST81_yLyb98QHbOOpO9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v -=XJ?|;InIPy66cFfOYp#JM2r7_Du?5Y;;Uvd1Z2QF#>u69p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#` -(<W`Nt;O}HAO^^zqT0%g+nC0;-MWK<)&Ge4`aq}l(*_A)b8}^MRAFax0(t`--)Viz@~C%8KNS}Z0aQ3s -^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr=x`Tq%|A_kfK&ST81`a}OX>Md`Zf8beV{~tF1pxpD -002NB01rcNZewL(Y-MCYbaY{3XaxZP2LJ#-AOH<RZ*F5{VQgh&L}7Gc1pxpD002NB01-oPZewL(Y-MCd -b#7;AVr*pw0t#bqZEb0EZDnqB0Z6?XZWsH8I~II?C0;dW+k!*yDqgzlqQwf$39g<|8VYh@Zf9jsa&K>D -0Z6?XZWsH8I~II?C0;dW+k!*yDqgzlqQwf$39g<|8VW;iZgg^CV{}Pm1pxpD002NB00~54bYW9;VRU5$ -0RRX906+i$000000096000000000R^cywiMb7^mG1`7jbW_AJEn^6;37FKqUhx?i3R+Mr!fY&(;2BFL( -m@EZk_srD_V{dMBa$#e1Nn`<^2rNlD$O59e#ogQsB77jPl+<X%NY5HtA>h5j^*S;IZf|a5WdHyO4P|(A -Wo~n6Z*Ek1aAg5xbsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez<ZDn*}WMOn+0rh%KI9Y!AFx9LC -k8@hQXE7w+qW3^C%eTEp@#^?_H3w&GZ(?C=a{=BXk!z-`g4hv-$6z_YxoLZ_neUP>BpbEf7FA*KKfDWJ -b8~5DZf#|5baMe=>KFFSbgda38zdDXQ<FRLb|SiQ9VaZ73zs1JxzuV1a%E&?Wo>0-0pHK5k@bh=O+>c= -6<h!*{FQ5)@y)40j$=5Ms=z9P=m~aVY-Mg^X=QT(-GycVZ((E+6z-1k*Q)plvl=9@swb(NvM}hX&nZVu -33g#@X=Gt^Z*l^910COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUE}_h5K%L=laq&yA1JoJ^{7>oKLk -F4~iax8KK|47hp+cWHEPWpi@^dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCp -fvNCW7iR%TNc7%ZG-!6Ur?3G54@G!%Wo~n6Z*Eg#Xk~3-1_lUiWprU=VRT^t2?2HFP59r=ivk<fM#zkx -BxA|e=9ERQ^Kdtnr}W_o38DZ1000000093000000000MPY;R&=Y;yn#0oCr34oQf!Y4K`P(FaQVwIle) -QgI&pHa%8Z1>xis%K<jQG@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^s(Ana000000093000000000Ma -Wn^V#ZF2w#0Y>fS!w4MxxaL=+DqP^k2!wz9AHH68xp8!<%Jqp^&Hw-a000000RI300000001IJrb7^O8 +0|;_uc4c8~Wn=&b0|awrVQc~+aI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP{|1C2;aNA(0eXS#L; +%_oib8;tKCLQ=nuAv#{`SnN;*b97;JWdSa-rT!PdFhnqz;9Q#<T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$ +dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%TNc7%ZG-!6Ur?3G5 +4ncEsX=iS2Wo~p-d2nR~0RR9389{S%X=iS2Wo~qHLTqVnWK(5fY*ctqbaDj&015$z{^Dg=h-~N_zJ`Re +d1EINWrM}GXaQb}6c#qIM2EQn4AaeCy`?<CYAbBntN_Pa2n4nlKIEL+qx65#t{Uro0000000000{{R30 +000007(sJ$X=iS2Wo~qHLTqVnWK(5fY*ct@WCZ~L3IT`y;$>KfZ0H=mhJ>?uV<!`3gT=OJ0bYv~7B;a& +hq(c*y!1S2^HuJ7Oiw7YF=1>so3EIu+3*)t78850@mnbX00000000300000000008L3DIsV`xca1pxpD +002NB01H8MbYWv?Q*>c;Wd;HQX=DL}aSf9!PV~dK2uo>;u!nFdemP_$e?^hl+JkM;eY!XaZDnL>VN`i= +WdTAkVTFju)T<OGK*#;b7c9-t{}BHTlYjt3e2ALe%y|w%VRL0eZ*6U9bZupBbOr?lW^7?+a{_t;9p7nv +%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<YPmV0dsu5sjwLjgQcrOsaG1F{QvR+LMR3-^ZN{xOxb4V`yb< +VM$~Glv2~%1FNg3QJ<&wKF}2F)J=UcKm7gx`duV?R0NO^33O>~Wpi|4ZEyepNCs(hb9H5M0(t`--)Viz +@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr=x`Tq%|A_kfK&ST81_)zlVQFqo +Wpn|p9zT>IUvP{mXY}ey+|ZdtG&qC*MSg*Y`lhfb^DEW}Lug@XZcb%%0|yRbX>?<6X>LtnX>M+1bN~-x +X>?<6X>L?yb98QHbTa`DVrg_^Z)t8+Wpi|HWpp$G4Pt3@V{d70Q)y>zWpo1$Vrg_^Z)t8)WoL9{b94j^ +Y-w?IX=F`dX>M+1bOjA;X>oOFWK?BybZ%vI1`k7TZewL(Y-MCYbaY{3XaxZP2LJ#-AOH<RZ*F5{VQgh& +L}7Gc1pxpD002NB01-oPZewL(Y-MCdb#7;AVr*pw0tI$qY;|P;ri?I=M@z~&!eWfal|+p!-KxbDp9M3O +tM)uqVFwo`4r6a_V`X7%Wn@HkZEbk~000U@Z*FvQVPkYjWCZ~L2LJ#-AOHzOVRT_rbYXO51pxpE002M$ +0000000030{{R3000009MR;^&ZgXjGZUzejW@dH)+M7`mSQb`xkca!3<yMq(Hh|YT3<jahB$zA(WcSR~ +3S)0>baG*1bV+0Zp9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b1#WL{V`TsU2n}U;bY*UHX>V>+ +d2nR`WOW`wsTH9-LlJ`2|Ay5Z(?oEikl{+~pis;@Q*TJ#2yJC_VPs)+VFC4eO*mP8`7qV21dnrCyk{{a +-lF$FG0V5TNAc?Tc{K-TY;R&=Y;ytLBav&Stb*7Pg~wnyz`1FAu$k|YFC-ha-WFA1@jtu^VRLh7XKrm} +Zgg`2S!nL7q2Ov9&rw<1inBEia8GNLssNy*7<GboFTDPr2y$g)Wo2z;WC7pLsgd=E<xNDl0To;TDg2dd +oAJ%5L5^cMma4!igXjr%VQgh?V`*h`0o{dW0B>Pr5ftu@@z<*O39}j`u&O7io3b$Is?RA$O$l~kY-wa+ +bZ>G3dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#llNeFa6}P}rq7L!(40)FbL%msz%JU8hqvFy +oea2o2X|?7Ze??G0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS-+`&{Sr=yk +NJ#YFTr_BQwWqKF0S`rZbY*UHX>V>*V`yb<VFm^WZDn*}WMOn+00{wg<W2bB&Wi#Y)kesSpCn_+*5;H& +uJdp=m8bOK2??SA00000000300000000007XKZg`VQg~%3IWybk`76TvuW{aQ_%-X`?VwZ$5L?~`!+pR +Sq0(b70UrO!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4rGOBq100000000300000000007a%E&?Wo>f+ +2?0j!=EDda{kY~=q$*tC#t4Le{2#tvcDZqMsmk?<S<V0e000000093000000000YNb8~5DZf#|5baMa- +0f+wLWmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdAr8G@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^ +s(Ana000000093000000000SgVQgh?V`*h`00{v`?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA7 +00000000300000000009c42I3WMOn~asUJZ00eGtZe;)f009JZZ*64&1pxwLa5aA+<>R2XhQO_4{AcS- +HH^7AVzASV8M4NYxyCka@1Z8)ymjIKNK5;L!8FkfGTe+FK;UUh9M-4n+}vReMR;^&ZgXjGZd7@2Wd#8M +00IL>W_ASu0006FMs;pyX<}?;Q*>c;Wds2T24ZP+b2c;p1pxp62n<GbZf9v?Y-Ln=aAgAl4RvmFX=iR_ +WHvNHX><q&M`dnhb7^x13j=0mb^+R(Q4?4eR(6nw`<dldlyWwJ*EtLZq0A(hECpou%+&~UV`yb<VM$~G +lv2~%1FNg3QJ<&wKF}2F)J=UcKm7gx`duV?R0NO^1!invXLAC210COKearHwcS=7M7YzYaI8*bvhMOc? +)(rkC#nUE}_h5K%L=laq&yA1JoJ^{7>oKLkF4~iax8KK|47hp;bZKp6b97;CZ~y>E25ED1b!Bn^w&;L{ +94K`ndk%K5+?9Jv$dw7jc}U5p5@2#$kUJ%u2xDkrX>LwsbOEg%Ka?O}aEvKu^y*67(3wRvID`L1eu0Pj +rm!gUE7k~YWprU=VRT^u^?FS>S$_F2)vN@Mb6UJ-F(lri_dqerx4lR4>iBsz2WM<=Vqt7^0p25#Yo@G% +*b#-tU^&3KX?w7l?~*Sh8@1jRRblZzybED-b7^O8ZDnqBa{*as?yI5TY8=l|S=)-UH4bo3Ym}-0prjae +f_E>x{+|hUVQgh?V`*h`0o{dW0B>Pr5ftu@@z<*O39}j`u&O7io3b$Is?RA$O$l~kY-wa+bZ>G3dIKHb +X?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#llNeFa6}P}rq7L!(40)FbL%msz%JU8hqvFyoea2o4M$~e +WpinBQ)6glZD9rl2yJC_VPs)+VE_pMb>vO>-_DBy8`Vb0jGrW9$=2qSMXvL3H<hRK;Ry+%0000000000 +{{R30000002WM<=Vqt7^015%s?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%<Q2;SHo-KZ`k;Xmr`<4s +JYKN!!u{G5u+^j1lf!PF4>GEG0000000000{{R30000003t@9}X=iS2Wo~qH015$z{^Dg=h-~N_zJ`Re +d1EINWrM}GXaQb}6c#qIM2EQnHo-KZ`k;Xmr`<4sJYKN!!u{G5u+^j1lf!PF4>GEG0000000000{{R30 +0000033g#@Wo~0>Wpe-t0Y>fS!w4MxxaL=+DqP^k2!wz9AHH68xp8!<%Jqp^&Hw-a000000RI3000000 +010+sY-wa+bZ>G11OfmAZf|a7000011aog~WdH>M0%CAAe<9`Lptgp<tz`UX>r6F_xjAC6(~TLj#*ewi +Hf`^rCgHqw;r~cW`-Q<Y(F`)&j2=MXX-gc|r|aC@VGBoWZ(?C=Q*>c;Wd#8M3IWybk`76TvuW{aQ_%-X +`?VwZ$5L?~`!+pRSq0(b70Uq%!}cPEJ+)wh?w~HsM>Kh32^DD>YKF13Ts`WEp!#kA000000003000000 +0000HM{I9mVQf=$VRU6vV`yb<VFm*Ta%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@O +CX@GIcyL4!ji%3ykI<Y<s&nfxrNA!QlZUt8$DItgdIfW3ZAoMTMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uM +rbA>C`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj2yJ0_Npxjxa{vGX4@YcoVqt7kbYXO5 +RC#b^1pxp60t`oNZ(?C=R$**)Wpf1q00;pxo>ox?`Aroor<$W|05z3@o%ygg<qMR;{BXa<eFTL800000 +00030{{R3000008Nn~YibZK;X1pxpB0s_h`9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3}KjBNr;@ +ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbd^20?I5NZ-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCrG{{ +7b@t4MVjY>G@u4Q3HlB(d+LiLJm-R=h;`?dxBvhE000000RImF0000000l{IaCLMB0taw%Wp+<>bODnP +ynwMZT8l5kSW@l}O=!>^xB4~9n`Dx!RtcK)nwJQ2Wpib6c4cG&dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0 +Th<KzD#g<#%eXB&=4kVCWpXCpfvNCW7iR%TNc7%ZG-!6Ur?3G52uW^mb#zT(a0LMX3Ig?P6JjIwIj2eq +liWu}$@z+_xPw?-wb>Rw7=FYk8VVufK10Q-T=FR=Q=>S+XYD&<oK4xzy{V5hX&1W5Lv;a_$mV(;bz)!C +mQ_M(k?Vd!kfCo{nDM?)_qK{868FUc0000000030{{R3000006Np5g;baMp(00{xrjb8{1n}Vi_2Sx(m +PtQ%C7;C?4Hp3VmIkXhJs^;PV0000000030{{R3000009O=V<hVN`i=Wdi{NVQzW<2u)>lVN`i=Wd#8M +00Ie3WprUyVQh6}1pxpE002M$0000000030{{R3000008O=WapWMOn+1pxpG0d?d}_}|Wp0vpvv$c&#P +W69R$ltr%da5t5w^x+8!q5%{oJdRMsrjHBJ^EIe4enz&iEACnc`NWk%>en!wdoTb1000000093000000 +000Y5V`Fu4a%FB~Wpf4s18r$;00065ZDDu-00In8a6@lxZE19EWo~o^3j=0mb^+R(Q4?4eR(6nw`<dld +lyWwJ*EtLZq0A(hECpou%+&>MZ*F5{000OEZ*Ww3aAg4vwe)9Jc)1;Ny;KQyMvhey?Qbc}K{+YF2{;w< +&v$4DZDn*}WMOn+0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr= +x`Tq%|A_kfK&ST81_x(sZ(?C=a{_t;9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<V5cLxv|61vo|< +S$`kJ6oIZx{|tq&1{dNqe!iO(;xh(mZg6#Ua{_t;9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<V5c +Lxv|61vo|<S$`kJ6oIZx{|tq&1{dNqe!iO(;xh|jb8~5DZf#|5baMiF10COKearHwcS=7M7YzYaI8*bv +hMOc?)(rkC#nUD@o<oKw6$Lm(8(DuJ#T0?AO#cjpum%_6G=9FD72-1pa%E&?Wo>0-0(t`--)Viz@~C%8 +KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr=x`Tq%|A_kfK&ST81_^dyY-Mg^X=QT) +dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#ZLh7x^`{^P$fKg#%8c8X#<$(NgM!uni2C|Kr}onZ +2X|?7Ze??G0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCODo$h9?yTI7S;;e;>sZfv!yd427@; +7veO2zMB=|GYNKKY-wa+bZ>G3dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#ZLh7x^`{^P$fKg# +%8c8X#<$(NgM!uni2C|Kr}onZ1W#~DWCZ~L2LJ#-AOHnVaBp>V1_J_bZ~>Lb=6W7=VqesjRYGc!>wZFz +p>JB4@xD;^wu&SY_r(Hqc>#z1;$>KfZ0H=mhJ>?uV<!`3gT=OJ0bYv~7B;a&hq(f7ZvX%S5Knh*Wn@!y +VRU6vV`yb<VFUyK3uI+uY+-U?bZK^F000012xfI|XK7+=WdH>M0r~W-2xhK9cV^W63=w?<vDsAp4rg8x +J7NUuaZl;xMgj_RbaHiLbairNWB>&L0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*=q!&6rQG) +02XJT?*g=|B=zREie$*y(7k2+*P~cYjROi{baY{3Xl-R~bN~eb0YWfgg^0-1s}v?c$Nk9{EX~mW5dRI6 +fB-~%h??EZc?eQvWMyS-Wn={b015#{?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA8mB{9L9(7`0 +)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<0000000000{{R30000004pL=yWnpY(WI=RvVPj|p0t9AhY-Irn +wto`e>uZ$?1z+)WysMU3t2e*Ff<cqP(7vcp9UG7Yb75?B000OKQe}2!VQgh&L}7Gc1_A|kVQh6}0WzLe +Q3m-<6)UHjqig^*m4co5us7ukl*0UQzs7w8g#>e9Y;*ts5D-#jc4c8~Wn@NmZf9v?Y-I)k1$JR<b!7pj +j4+W$OUgRJVvNU?M2#%ns>Kwa1v8ba_B>T#2Nxy=Q)6glZD9rt17>D+0ot2U6Id2jc94hrndMfLayEe1 +ISdA&%p{mB1!VWk)dgm3VP|s!dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#llNeFa6}P}rq7L! +(40)FbL%msz%JU8hqvFyoea2o1a4t%WdcR&qhH(h<B$P5@#5`<3V$8+S7~5Qj4-A{WE1=O5ZO}}2!s^L +f^?|9I@Xg>Oi(W05|TJ%PM*ricn_PmXk-a=X>Db5bYX39002k{WMy_`Y;SO7asjsJfQB3>bs~EXcCXx( +drQcb3B`Fx$)^%va$Ar)C7cOuWprUwd2nTO015$h<W2bB&Wi#Y)kesSpCn_+*5;H&uJdp=m8bOK2??SC +Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj +0000000000{{R30000003ukO^Vqt7ld2nTO015%s?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%<Q2;S +QxVNWsw`2k$dAVYYJsYG;e2<6^ZE|08<d;*WV8Gk0000000000{{R30000003U7CAWn@%&aAk7<3IT`y +;$>KfZ0H=mhJ>?uV<!`3gT=OJ0bYv~7B;a&hq(bIMRdNwxo;<I#w{j{Xn5DV2yMQyJM8PZwdbUS!cOu4 +0000000030000000000Cc42H~Zew{=d2nTO00{v`?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA7 +00000000300000000007XJu|>b7^w{7)aIA#9XnshcC})U)TI#r3b0kyqD7}ejM+$yUGm(3T1e7Wo~n6 +Z*Fq{3ISww9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZtVhXadZr-S<kMvlS1-a+|}YjA26r&2rkD +ZzcBl<qg~b0000000030000000000BbaG*Cb7^#GZ*Fq{3IQ}y53UoI8eY9A{1GERg--GiI0S#x1is&) +M%fmnGH3yIwHs)QqWhh6&a)9BiaoJZ>PY!h`6Z9%SYt5l1;p3@00000000300000000008a%FR6a&~28 +0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCjNpJN#A(BKKz&v`r;e6DUv<<*U}c<e%g}v1+@9m +9tcxoXk~3-Nn`~900#g7Kp+4LRB~Z%b7^#GZ*B$)17>D+0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB +1!VWk)e2*8Zgg^CV{}Pm0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6imLZewKt00<6ra$#<B +X>@6CZd7@2WdSr&53UoI8eY9A{1GERg--GiI0S#x1is&)M%fmnGH3{GWprU=VRT^u^?FS>S$_F2)vN@M +b6UJ-F(lri_dqerx4lR4>iBsz2WM<=Vqt7^0p25#Yo@G%*b#-tU^&3KX?w7l?~*Sh8@1jRRblZzyas7* +aCLNZ0jZ*TSChz_$|Xx}eRkFNAr%^eLl(1e@}~9=0-ijXfD2)Bb7^O8ZDnqBa{(ht>-pde{GkuQzBXTA +in>IdF&9PAZ4eqJ|JRcX$HfVDVQgh?V`*h`0o{dW0B>Pr5ftu@@z<*O39}j`u&O7io3b$Is?RA$O$l~k +Y-wa+bZ>G3dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#llNeFa6}P}rq7L!(40)FbL%msz%JU8 +hqvFyoea2o2X|?7Ze??G0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS-+`&{ +Sr=ykNJ#YFTr_BQwWqKF0T5JjVQzD2bZKvHLUnFrY-I)l2x)F`b#zT(Z~+yWXJpH@t3U@-^C5At>@@qQ +FQ2KNd+8eYXv4en`-l*0Zf|#PRB~Z%b7^#GZ*Fq{3IUbK=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY +_r(DzL|e#IO-TAgsp%#NX)%c(fjr3)`APEDlE~V`A*D$H0000000030{{R300000GRB~Z%b7^#GZ*Eg# +Xk~3-1_lUiWprU=VRT^t2?2HFP59r=ivk<fM#zkxBxA|e=9ERQ^Kdtnr}W_o38DZ1000000093000000 +000MPY;R&=Y;yn#0oCr34oQf!Y4K`P(FaQVwIle)QgI&pHa%8Z1>xis%K<jQG@<&SffJ|QFn~N>u=2wF ++7z(Wqt=tdZk`V^s(Ana000000093000000000JQZg6#Ua{vkfhyLPaScq)s9KMExvw34D6J>+NwrBxf +ixd_%u|$Wt0XD%jq57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI300000001IJrb7^O8 ZDnqBa{vkfhyLPaScq)s9KMExvw34D6J>+NwrBxfixd_%u|$Wt0XD%jq57bK6Q|uUfIMEX^1}Vv6tLB! )|10-o)0prc>n+a000000RI3000000010+sY-Mg^X=QT&2?0j!=EDda{kY~=q$*tC#t4Le{2#tvcDZqM smk?<S<V0e000000093000000000SgVQgt+VRUbD00aU61a5C`WdHyG0R(ezZDjxj0Rm!hHGd)H<Dj;N -z^!EbXX{KgjJY{tu+xnhvc`|O#x`y5p(f$Hb>aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++htxcywiMb7^mG -RC#b^1pxp60s}^7b_D?d00Iq0b#7;AVr*qobYXO51OW&JVrg`9HZ%YQ0RR993`TWsXK7+=WmI`^Wdi{X -b#8NMXKrO=HZ($MbO;AWWo~72X>$e*17>D+0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)d+KA -Xk~3-Nn`<(Qq$W5tE;F{pQrXd&=l*`O?@#x{Qdy?T_k!`1dtE~W^7?+a{_t;9p7nv%krpqN<S4B4FOa* -Q}elon<QJ-4E`#`(<YPmV0dsu5sjwLjgQcrOsaG1F{QvR+LMR3-^ZN{xOxe6X>Db5bYX39002k^X>)UR -WpV+w=zxYCD0L!x4tB5Hm3vFbl?lapNXe%XU~*fKJ0+Y4bY*jNZe?@=$}AplgPGkh3_fq3Q7_j=2#kPT -_9!;lWR>~GYywm#VTK~nd#><i0^jF#$$;RqYi_#e2@QaC_fb3SOOy6Z3Sn$?OksIta&s{OBv(?{Wq|OU -%4#DwR1!oWV0@!2f9}lj6c7M!3JEHV31M?{Wpq?wXLA85B@PC`naz9~L0@lerBKV`$$1fC6#s{=m+2p6 -@mtIYZDn*}WMOn+0rh%KI9Y!AFx9LCk8@hQXE7w+qW3^C%eTEp@#^?_H3w&GZ(?C=a{=BXk!z-`g4hv- -$6z_YxoLZ_neUP>BpbEf7FA*KKfDWJb8~5DZf#|5baMe=>KFFSbgda38zdDXQ<FRLb|SiQ9VaZ73zs1J -xzuV2c42H~ZewX>a{=9jW&m$tWDykZj`7#3_zANbB(SO{shhGe=&H{tM@<QKVQgt+VRUbD0(t`--)Viz -@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCX@GIcyL4!ji%3ykI<Y<s&nfxrNA!QlZUt8$DItgdJRWqZe??6 -b5mnzWo=;w1qf|rbYWy+bYTDq0d?d}_}|Wp0vpvv$c&#PW69R$ltr%da5t5w^x+8!q5uE@000000RI30 -0000000(DmZ(?C=a{vkf)$WoGNr<y)@oH1i2TJ?3BlyQsaUT0NJyux-;p7#|0XD%jq57bK6Q|uUfIMEX -^1}Vv6tLB!)|10-o)0prc>n+a000000RI300000001IJrb7^O8ZDnqBa{vkfhyLPaScq)s9KMExvw34D -6J>+NwrBxfixd_%u|$Wt0XD%jq57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI3000000 -010+sY-Mg^X=QT&2?0j!=EDda{kY~=q$*tC#t4Le{2#tvcDZqMsmk?<S<V0e000000093000000000Sg -VQgt+VRUbD00aU61a5C`WdHyG0R(ezZDjxj0Rm!hHGd)H<Dj;Nz^!EbXX{KgjJY{tu+xnhvc`|O#x`y5 -p(f$Hb>aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++hnxY;R&=Y*Tb$bY%qr015%s?vf5kh_h+&YE#h%O8d1V -_{UOl9{V;uR#^q%<Q2;S3d8myhCQ`lg6^O$%||qOV+j>$8ES^HwOl>wiJ<y!0000000000{{R3000000 -5l3uqVqt7kbYXO5Q)6glZD9rj2y$g}WpZ|9WCD5v9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<YPm -V0dsu5sjwLjgQcrOsaG1F{QvR+LMR3-^ZN{xOxS1Wo=1h0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If -6Z`oP*=q!&6rQG)02XJT?*g=|B=zREie$*y(7k2+*P~cYjR<XFcu90+ZF2ws0}n@RZ(?C=Q*>c;WmI`^ -Wd#8M00In0Y;R&=Y*t}xb!Bq}0RRXAGM-jZ2Kh}DE2o;HYydTtf}Q!WH{}bI!u)W*#(e~Z0RR9100000 -|Nj60000002uWmRZggpMc?AIg1p)%fEFN!zncXl9K5w2;FV{y1jDTJCC^p$-mHEbO0#qkRz9SbZ=!8X@ -=Yuq$20sb<4l#S`iz7Vef}@Ca=a#qt2m;D19&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3}KjBNr;@ -ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbd@_000000093F00000000F^Zg6#U1_B3ga%FZ;b#wuf5WIk~ -G+K)<!&p-84^3#$9k=>5%bR49t5yk`^qQ9la%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D -{wl@OCd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0SHNMaCLM|VQ>Wj015*2Y!hN5_Bp3Y36tDM -M#=e#tGI($UA5U3KNx<*C>jbO<32;hs$B9ZCsU(1!DsC|W1LOd&b_IRG-(&Q$wPGkmB{9L9(7`0)Rt93 -YLV-HLXe?vTA1;^Q1`ZqBog<<0RR9100000|Nj600000021#ykb#!wD0RRaB)s0^W44Z<ciU&pl;7`v@ -pBQVuYc|6e9yzoWyQ=2m0000000000|Nj60000002~A~WX<<}(aAgAl17U7?{|HTGbYWC^aAgGn0006B -O=WapR$**)Wd#8M2mk;;0000000000|Nj60000002u)>lVPs)+VFdvI3ITQGP59r=ivk<fM#zkxBxA|e -=9ERQ^Kdtnr}W_o38DcMB|MH$#iox7(epK^GJZz3uq*Cb2l>R6Lh9EroO>_;0000000030000000000B -Ph(?sa&l#EV`Xy&0t0PnZU6uR18re=0006EPjEwTZEb0EZDnqB1`7jbW_AJEn^6;37FKqUhx?i3R+Mr! -fY&(;2BFL(m@EZk_srD=Zf|a5WdHyO25)dwd2nR`=kby$tK%HuPpRtMKe5+wDRP}k(QuARKUbDjTz^bE -2yJC_VPs)+VFG#s9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<W`Nt;O}HAO^^zqT0%g+nC0;-MWK< -)&Ge4`aq}l(*_4;Y;R&=Y;yv710COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUD@o<oKw6$Lm(8(DuJ -#T0?AO#cjpum%_6G=9FD72-1nX>M?JbaMiF10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUD@o<oKw -6$Lm(8(DuJ#T0?AO#cjpum%_6G=9FD72-1sVRLh7XKrm}Zgg`3dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0 -Th<KzD#g<#IG#g>Clv)aMjKgwAH@`bu1x<7g|G$};xvA~n-$_S2y$g)Wo2z;WCD5v9p7nv%krpqN<S4B -4FOa*Q}elon<QJ-4E`#`(<W`Nt;O}HAO^^zqT0%g+nC0;-MWK<)&Ge4`aq}l(*_B4VQgh?V`*h`0(t`- --)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr=x`Tq%|A_kfK&ST81_yU( -bZ%vHa{_t;9p7nv%krpqN<S4B4FOa*Q}elon<QJ-4E`#`(<V5cLxv|61vo|<S$`kJ6oIZx{|tq&1{dNq -e!iO(;xh?$VQgt+VRUbD0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXE -n8vr=x`Tq%|A_kfK&ST81_V!VNn`~900#g7Kp+4GPjGK_bOr+gZ*T#X$mV(;bz)!CmQ_M(k?Vd!kfCo{ -nDM?)_qK{868FUdba?@X{^Dg=h-~N_zJ`Red1EINWrM}GXaQb}6c#qIM2EQoZf^hp0uWDkZe?UsbYXO5 -Q)6glZD9li01ISgV{Bn^VRUJBWdHyG0SIPwZf9v?Y-Ioi0Rj2+tO#bVL3d`<{R|O(1hLsv{SIed5<6l9 ->v2!%<wgPub98cbV{~<LWn=&a0RlzpqhH(h<B$P5@#5`<3V$8+S7~5Qj4-A{WE1=O5ZP-4qZFQ|l>ioJ -pYH;+t0eX2w~A!Q+0eaZ{MVycPK^T!VRUq1V`yz<Zgc<z0RciVVTFju)T<OGK*#;b7c9-t{}BHTlYjt3 -e2ALe%y|+}Wn^V?b7gKrZ*6U9bZupBbOiwb2LJ#-Api(cWn^V#ZDnKy0RRdCM(yUq2ps*m=2xUDT;RqC -gn#@WzFu~@adfH5^@&-|0hP$+dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#Q*>R000000RI3000000 -01i@Rc4c8~Wn@8gbYWv?1_A_TX>4Ty3ATR{-|K6Y3I$*BbiAvUS*tg{!Gb}P!O*^_P#qhP1ao0*bN~Pd -3{quwWnpY(WJF<fVFm&Pc42IFWdSmtR#67|O%*Grnxkw0HI;&$`LH+T3zWkAaKFZV1cd~1VQh2&01yyT -Wp-s@Y-MCdb#7;AVr*pw0|j<rY;|P;ri?I=M@z~&!eWfal|+p!-KxbDp9M3OtM)uqVFwo`2x4q$Ze(e0 -X90z{_$#~gq^1qCzduE|50q|rgTt*-ZIkqGqXDRHN7@5)VP^r!kD95&21^?K{bw7Oyej<uOlXfEbI2|0 -ac}2on<B3UQ)6glZD9rt17>D+0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)dgm3VP|s!dIKHb -X?@G`sCP;~6&DQwR5(-fxrUo0Th<KzD#g<#llNeFa6}P}rq7L!(40)FbL%msz%JU8hqvFyoea2o1a4t% -WdcR&qhH(h<B$P5@#5`<3V$8+S7~5Qj4-A{WE1=O5ZO}}2!s^Lf^?|9I@Xg>Oi(W05|TJ%PM*ricn_Pm -Xk-a=X>Db5bYX39002k{WMy_`Y;SO7asjsJfQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7cOuWprUw -d2nTO015$h<W2bB&Wi#Y)kesSpCn_+*5;H&uJdp=m8bOK2??SCMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uM -rbA>C`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj0000000000{{R30000003ukO^Vqt7l -d2nTO015%s?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%<Q2;SQxVNWsw`2k$dAVYYJsYG;e2<6^ZE|0 -8<d;*WV8Gk0000000000{{R30000003U7CAWn@%&aAk7<3IT`y;$>KfZ0H=mhJ>?uV<!`3gT=OJ0bYv~ -7B;a&hq(bIMRdNwxo;<I#w{j{Xn5DV2yMQyJM8PZwdbUS!cOu40000000030000000000Cc42H~Zew{= -d2nTO00{v`?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA700000000300000000007XJu|>b7^w{ -7)aIA#9XnshcC})U)TI#r3b0kyqD7}ejM+$yUGm(3T1e7Wo~n6Z*Fq{3ISww9zv-Vp*%wog4O?q)g04A -aHEjnO6;Ie%sNwVNZtVhXadZr-S<kMvlS1-a+|}YjA26r&2rkDZzcBl<qg~b0000000030000000000B -baG*Cb7^#GZ*Fq{3IQ}y53UoI8eY9A{1GERg--GiI0S#x1is&)M%fmnGH3yIwHs)QqWhh6&a)9BiaoJZ ->PY!h`6Z9%SYt5l1;p3@00000000300000000008a%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqb -BwN-D{wl@OCjNpJN#A(BKKz&v`r;e6DUv<<*U}c<e%g}v1+@9m9tcxoXk~3-Nn`~900#g7Kp+4LRB~Z% -b7^#GZ*B$)17>D+0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)e2*8Zgg^CV{}Pm0iOsgNjk^^ -qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6imLZewKt00<6ra$#<BX>@6CZd7@2WdSr&53UoI8eY9A{1GER -g--GiI0S#x1is&)M%fmnGH3{GWprU=VRT^u^?FS>S$_F2)vN@Mb6UJ-F(lri_dqerx4lR4>iBsz2WM<= -Vqt7^0p25#Yo@G%*b#-tU^&3KX?w7l?~*Sh8@1jRRblZzyas7*aCLNZ0jZ*TSChz_$|Xx}eRkFNAr%^e -Ll(1e@}~9=0-ijXfD2)Bb7^O8ZDnqBa{)s3lIz?v1U>x&T2C;PAKlCCveQ{N4udSh#@3Dqj&%ukVQgh? -V`*h`0o{dW0B>Pr5ftu@@z<*O39}j`u&O7io3b$Is?RA$O$l~kY-wa+bZ>G3dIKHbX?@G`sCP;~6&DQw -R5(-fxrUo0Th<KzD#g<#llNeFa6}P}rq7L!(40)FbL%msz%JU8hqvFyoea2o2X|?7Ze??G0(t`--)Viz -@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0T5JjVQzD2 -bZKvHLUnFrY-I)m3uA0=b7f6sbZBp60#*~&*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3ONG`V!CAn^8 -7TS9h9ibhaZ&^Bcn*B*;w|~I;-PD|t>j-IXaCLM|VQ>KznP+6nwW~k}RP!Nmu<SJZr!SwWo_pyU_h`er -^ZSSpYi@6MZd7t%ZgXjLX>V?G015$>$mV(;bz)!CmQ_M(k?Vd!kfCo{nDM?)_qK{868FUc))-~W22H5+ -SDrhMohTRsfLT>C1dS{r3#^{o?N>fE0RR9100000|Nj60000005L9wuZgXjLX>V>*V`yb<VFm^WZDn*} -WMOn+00{wg<W2bB&Wi#Y)kesSpCn_+*5;H&uJdp=m8bOK2??SA00000000300000000007XKZg`VQg~% -3IWybk`76TvuW{aQ_%-X`?VwZ$5L?~`!+pRSq0(b70UrO!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4r -GOBq100000000300000000006X>M?JbaMa-0f+wLWmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdAr8 -G@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^s(Ana000000093000000000YNb8~5DZf#|5baMa-0f+wL -Wmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdAr8G@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^s(Ana -000000093000000000SgVQgh?V`*h`00{v`?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA700000 -000300000000009c42I3WMOn~asUJZ00eGtZe;)f009JZZ*64&1pxwLa5aA+<>R2XhQO_4{AcS-HH^7A -VzASV8M4NYxyCka@1Z8)ymjIKNK5;L!8FkfGTe+FK;UUh9M-4n+}vRfRB~Z%b7^#GZ*Ek1aAgGn0006G -RC#b^LvL+uX>@I6Zgd0#00(DfZe??6a{vVa0W)M-Q2pM493%15wcJ8Z{z5k9VD)f0JnAj^7J5MZ9{~z< -a$#<BX>@6CZU6-W0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G66JF53UoI8eY9A{1GERg--Gi -I0S#x1is&)M%fmnGH3z`Wq5RDZgXjGZU6-W0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G67_D -9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZuM$d2nT9L349yXKr&sY-w&}Q)OXnRCrKyas&hb3uI+u -Y+-U?bZK^F00jX62mv`K^WREqS2tt~EBII@xVqZNcP`ond^UU-JbUWd$~FK100000009600000000039 -W_507X<}?;00jX62m#u~=^e=I{=p`1zMng|0+NmwUpUW`Z@54^_oW>WVpRYD0000000960000000006C -b98cbV{~<LWn=&a0RRXAfgb0V4v@cHO73HjlbgFm42mCs2<+~e+;O=m63^mM0000000000|Nj6000000 -{|aGrbYWv?ZDnqB00jX62m#i-GqJ&TQwZPkn|ZOr{h9VNEFkRYIec?G`g2UV1s4DS000000096000000 -000?Od2nT9L349yXKr&sY-w&}Q)OXnRCsA*1OxyJWMyM)VRB(~X?A4*1pxpE0h7R#ToRU7hj7<ub#3oL -9G%~^w2aPqMVq7Wx@kSgE&u=k000000RR6000000009VQb#7;AVr*pq1pxpE0sqoR=7&`Kq#Oqj05T(3 -bv<N6q^l&d3LB)t`g=~H!T<mO000000RR600000000IhgbaHiLbairNWB>&L00;qEk8=qnO(R<<%JIK< -1B78x*e6}1oxDzJ3ElvocGBqp0000000030{{R30000303So3~VPj}*Wo~o;1pxpE0aMUzRzj^*Tk1C) -pGbjYG7<A7KSzLp8YcAU26U8~O8@`>000000RR600000000~xMY-Mg^X=QT-0RRaBM(yUq2ps*m=2xUD -T;RqCgn#@WzFu~@adfH5^@&-|0000000000{{R30000003szxlWo~16RC#b^1pxp60tr@cX=GD$VRU5$ -0RR916j(!OVQFqcY-w&}Q)OXnRCrKyas&bZ2V!Y-V{d7000jX8Ruk6O)Q5AKbFW;JEQ>MoHhG*Mzd(pE -tONi$rOUxcMklB)P_)|`Y=H7dO_e!^G2i>0SdC0NppV!6v|_i_0S0Voadl~A00jX8Ruk6O)Q5AKbFW;J -EQ>MoHhG*Mzd(pEtONi$rOUxcMklB)P_)|`Y=H7dO_e!^G2i>0SdC0NppV!6v|_i_6IerNVQFqcY-w&} -Q)OXnRCsA*1OfmDVrg_^Z)t7-1pxw96V}(%hjW>8uUwNXi!t*yd7K}=K!`A`1OPgv%fU#n#&NEOd)wn+ -n#11fGQ~$X901P7x>0daZB@{PThHqO25f0@b!lV(1pxw96V}(%hjW>8uUwNXi!t*yd7K}=K!`A`1OPgv -%fU#n#&NEOd)wn+n#11fGQ~$X901P7x>0daZB@{PThHqdSVL%GX>L<xV{&D5Q)OXn1OfmDVrg_^Z)t7- -1pxw96V}(%hjW>8uUwNXi!t*yd7K}=K!`A`1OPgv%fU!!8SA{&vly$FvzVnzHf7z~rv`86=_Ka^V5yX| -y#`JJ25f0@b!lV(1pxw96V}(%hjW>8uUwNXi!t*yd7K}=K!`A`1OPgv%fU!!8SA{&vly$FvzVnzHf7z~ -rv`86=_Ka^V5yX|y#`JSSVL%GX>L?_X=DTf00&}ebYpL6ZU6-V0`+VYVk7oBr%DNv+($;q`HHK!gIHa) -*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1RsjZVX>oOFWB>&L0`+VYVk7oBr%DNv -+($;q`HHK!gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1Rs +z^!EbXX{KgjJY{tu+xnhvc`|O#x`y5p(f$Hb>aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++hw>a$#<BX>@6C +Zd7@2Wd#8M00ItFd2nSzZ*6U9bZupBbOZwc2WMq&WpinB00jX7vJ_W)4b;Oq(9r82ndje7Ko)~URBn_V +i`WE%_0zpa0Sa_-VQzD2bZKvH00ja8p9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0W?w%t`n9T +UcD*&5hFi^PVx{q1b@^7zTcrn*%qZTXaWgkcywiMb7^mG00ja8p9m~TI>-W|y2ahx3nF|Vuawki#7NH? +S|Q-Q!u2{b0c3R^La7y@JVOzJ)&GXo9MeQ_qmbcB?4VH0I#X{*-WpVSaAjmcb8~5DZgWCxX>MdwWnpYo +cu;h51OxyJWMyM)VRB(~X?A4*1pxpE0VJYLy~((>QDk-Reb6>u4I6~IunL?`sHIMQRAusB@&Et;00000 +0RR6000000009VQb#7;AVr*pq1pxpE0i_o*B<$FGIkF5XQSMf{_M@c9%UhlKoi7vOr;j@`5&!@I00000 +0RR600000000IhgbaHiLbairNWB>&L00;qp&4>-QG26VF*-S^-{`Ty<Zim=D{OY|Z7#Mkd{sMvk00000 +00030{{R30000303So3~VPj}*Wo~o;1pxpE0nJpULVZ3RTs2kXr}a+n5Z2K<(@D&*z)_cnO7;6+!2kdN +000000RR600000002x$yaAjmcb8~5DZgWCxX>MdwWnpYocxhw=1ON+UWn*k%a$$67c4Yts0RRXA(ioHU +?OAt%_ub?z3CQcz?b&Jzv^dc|DXMwk^XsLo0000000000|Nj60000000SIPwZf9v?Y-Ioi0RRXAEz*5S +r(qVbRr(sgSTLXWu*DC!3`08H_Vqrgg&j6`0000000000|Nj60000000t$0<a&=>Lb#i5700jX62mzn_ +Vu(Kcnq2_}AwBsWF~zA4={E`N$>>@ZV#d(SIc@*|0000000960000000093AVRUq1V`yz<Zgc<z0RRXA +Zp_q%d_mgImp4GfV;Qb&l7vdD@rH--Eb>v<x{H~q0000000000|Nj6000000307fjWo~0>Wpf1q00{v` +?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA70000000030000000000BR$**qZew{=d2nR~0RR93 +307}uWK(oubY%qr0000 -----END STRICT TYPE LIB----- diff --git a/stl/RGBCommit@0.1.0.stl b/stl/RGBCommit@0.1.0.stl index 00268c22..760cfd78 100644 Binary files a/stl/RGBCommit@0.1.0.stl and b/stl/RGBCommit@0.1.0.stl differ diff --git a/stl/RGBCommit@0.1.0.sty b/stl/RGBCommit@0.1.0.sty index 2f28c663..338d7f9f 100644 --- a/stl/RGBCommit@0.1.0.sty +++ b/stl/RGBCommit@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:IFcnrPeI-TANxLfZ-feJax6Q-1TUM4Hq-AjI161s-3tbmxak#harvest-person-orion + Id: stl:n4BoS9Kd-oZ1mUgb-6Hqg9hY-q$JXa84-YoWed1a-!6AZCTM#raymond-open-organic Name: RGBCommit Version: 0.1.0 Description: Consensus commitment layer for RGB smart contracts @@ -11,17 +11,16 @@ @context typelib RGBCommit +import BPCore#symbol-tropic-grand + use BlindSealTxid#halt-crash-valid + use SecretSeal#dollar-iris-wizard + use BlindSealTxPtr#content-paradox-dominic + use TxPtr#italian-july-eddie + import StrictTypes#century-comrade-chess use TypeName#edgar-carol-mystery use SemId#logic-absorb-hilton -import BPCore#austin-story-retro - use Method#bali-boris-plasma - use BlindSealTxPtr#fortune-iron-salmon - use SecretSeal#dollar-iris-wizard - use BlindSealTxid#media-judge-anita - use TxPtr#italian-july-eddie - import AluVM#congo-archive-folio use LibSite#ultra-grace-message use LibId#germany-culture-olivia @@ -35,7 +34,6 @@ import CommitVerify#miller-pancake-elastic import Std#ralph-blue-lucky use AsciiPrintable#ultra-sunset-format - use Bool#oxygen-complex-duet use AlphaNumLodash#percent-bingo-caesar use AlphaCapsLodash#duet-hammer-labor @@ -44,128 +42,115 @@ import Bitcoin#signal-color-cipher use Txid#shallow-light-reverse -@mnemonic(edison-survive-nitro) -data AltLayer1 : liquid#1 | (|) - - -@mnemonic(almond-office-pulse) -data AltLayer1Set : {AltLayer1 ^ ..0xff} - -@mnemonic(slang-amber-club) -data AssetTag : [Byte ^ 32] - -@mnemonic(crash-singer-corner) -data AssetTags : {AssignmentType -> ^ ..0xff AssetTag} - -@mnemonic(airport-ladder-joseph) -data AssignRevealedAttachBlindSealTxPtr : confidential (seal XChainSecretSeal +@mnemonic(credit-cycle-panama) +data AssignRevealedAttachBlindSealTxPtr : confidential (seal BPCore.SecretSeal , state ConcealedAttach , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr + | confidentialState (seal BPCore.BlindSealTxPtr , state ConcealedAttach , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state RevealedAttach , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr + | revealed (seal BPCore.BlindSealTxPtr , state RevealedAttach , lock CommitVerify.ReservedBytes2) -@mnemonic(member-camera-parking) -data AssignRevealedAttachBlindSealTxid : confidential (seal XChainSecretSeal +@mnemonic(volcano-chariot-plastic) +data AssignRevealedAttachBlindSealTxid : confidential (seal BPCore.SecretSeal , state ConcealedAttach , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid + | confidentialState (seal BPCore.BlindSealTxid , state ConcealedAttach , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state RevealedAttach , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid + | revealed (seal BPCore.BlindSealTxid , state RevealedAttach , lock CommitVerify.ReservedBytes2) -@mnemonic(genius-editor-formula) -data AssignRevealedDataBlindSealTxPtr : confidential (seal XChainSecretSeal +@mnemonic(sweden-alpine-quality) +data AssignRevealedDataBlindSealTxPtr : confidential (seal BPCore.SecretSeal , state ConcealedData , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr + | confidentialState (seal BPCore.BlindSealTxPtr , state ConcealedData , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state RevealedData , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr + | revealed (seal BPCore.BlindSealTxPtr , state RevealedData , lock CommitVerify.ReservedBytes2) -@mnemonic(soda-edison-music) -data AssignRevealedDataBlindSealTxid : confidential (seal XChainSecretSeal +@mnemonic(break-python-verona) +data AssignRevealedDataBlindSealTxid : confidential (seal BPCore.SecretSeal , state ConcealedData , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid + | confidentialState (seal BPCore.BlindSealTxid , state ConcealedData , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state RevealedData , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid + | revealed (seal BPCore.BlindSealTxid , state RevealedData , lock CommitVerify.ReservedBytes2) -@mnemonic(rachel-unique-logic) -data AssignRevealedValueBlindSealTxPtr : confidential (seal XChainSecretSeal +@mnemonic(basic-elastic-digital) +data AssignRevealedValueBlindSealTxPtr : confidential (seal BPCore.SecretSeal , state ConcealedFungible , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr + | confidentialState (seal BPCore.BlindSealTxPtr , state ConcealedFungible , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state RevealedFungible , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr + | revealed (seal BPCore.BlindSealTxPtr , state RevealedFungible , lock CommitVerify.ReservedBytes2) -@mnemonic(cadet-book-pablo) -data AssignRevealedValueBlindSealTxid : confidential (seal XChainSecretSeal +@mnemonic(example-reply-lorenzo) +data AssignRevealedValueBlindSealTxid : confidential (seal BPCore.SecretSeal , state ConcealedFungible , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid + | confidentialState (seal BPCore.BlindSealTxid , state ConcealedFungible , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state RevealedFungible , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid + | revealed (seal BPCore.BlindSealTxid , state RevealedFungible , lock CommitVerify.ReservedBytes2) -@mnemonic(cycle-panther-cave) -data AssignVoidStateBlindSealTxPtr : confidential (seal XChainSecretSeal +@mnemonic(snow-adrian-cadet) +data AssignVoidStateBlindSealTxPtr : confidential (seal BPCore.SecretSeal , state VoidState , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr + | confidentialState (seal BPCore.BlindSealTxPtr , state VoidState , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state VoidState , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr + | revealed (seal BPCore.BlindSealTxPtr , state VoidState , lock CommitVerify.ReservedBytes2) -@mnemonic(dynasty-iron-athena) -data AssignVoidStateBlindSealTxid : confidential (seal XChainSecretSeal +@mnemonic(drum-cover-between) +data AssignVoidStateBlindSealTxid : confidential (seal BPCore.SecretSeal , state VoidState , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid + | confidentialState (seal BPCore.BlindSealTxid , state VoidState , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal + | confidentialSeal (seal BPCore.SecretSeal , state VoidState , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid + | revealed (seal BPCore.BlindSealTxid , state VoidState , lock CommitVerify.ReservedBytes2) @@ -184,17 +169,17 @@ data AttachId : [Byte ^ 32] @mnemonic(harvard-burma-bicycle) data AttachState : id AttachId, mediaType MediaType -@mnemonic(amadeus-sunday-casino) +@mnemonic(stadium-stadium-vacuum) data BaseCommitment : flags CommitVerify.ReservedBytes1 , schemaId SchemaId , timestamp I64 , issuer CommitVerify.StrictHash - , testnet Std.Bool - , altLayers1 CommitVerify.StrictHash - , assetTags CommitVerify.StrictHash + , chainNet ChainNet + +@mnemonic(ringo-fashion-enrico) +data ChainNet : bitcoinMainnet | bitcoinTestnet3 | bitcoinTestnet4 | bitcoinSignet + | bitcoinRegtest | liquidMainnet | liquidTestnet -@mnemonic(animal-plume-minus) -data BlindingFactor : [Byte ^ 32] @mnemonic(meter-arizona-albino) data ConcealedAttach : [Byte ^ 32] @@ -202,8 +187,8 @@ data ConcealedAttach : [Byte ^ 32] @mnemonic(ivan-tripod-young) data ConcealedData : [Byte ^ 32] -@mnemonic(arizona-basic-moment) -data ConcealedFungible : commitment PedersenCommitment, rangeProof PedersenCommitment +@mnemonic(justice-border-griffin) +data ConcealedFungible : value FungibleState, concealedDummy () @mnemonic(uniform-welcome-papa) data ContractId : [Byte ^ 32] @@ -245,15 +230,13 @@ data FungibleState : bits64#8 U64 | (|) data FungibleType : unsigned64Bit#8 | (|) -@mnemonic(fashion-delta-polka) +@mnemonic(bazooka-couple-summer) data Genesis : ffv Ffv , schemaId SchemaId , flags CommitVerify.ReservedBytes1 , timestamp I64 , issuer Identity - , testnet Std.Bool - , altLayers1 AltLayer1Set - , assetTags AssetTags + , chainNet ChainNet , metadata Metadata , globals GlobalState , assignments AssignmentsBlindSealTxid @@ -336,9 +319,6 @@ data OwnedStateSchema : declarative () | structured StrictTypes.SemId | attachment MediaType -@mnemonic(pupil-scale-jerome) -data PedersenCommitment : [Byte ^ 33] - @mnemonic(anita-vega-pirate) data Redeemed : {ValencyType -> ^ ..0xff OpId} @@ -348,10 +328,8 @@ data RevealedAttach : file AttachState, salt U64 @mnemonic(sleep-source-figure) data RevealedData : value DataState, salt U128 -@mnemonic(source-contact-member) +@mnemonic(escape-nylon-client) data RevealedFungible : value FungibleState - , blinding BlindingFactor - , tag AssetTag @mnemonic(corona-igloo-sierra) data Schema : ffv Ffv @@ -384,10 +362,8 @@ data Transition : ffv Ffv , validator CommitVerify.ReservedBytes1 , witness CommitVerify.ReservedBytes2 -@mnemonic(antonio-adios-analyze) -data TransitionBundle : closeMethod BPCore.Method - , inputMap InputMap - , knownTransitions {OpId -> ^ 1.. Transition} +@mnemonic(rider-serpent-algebra) +data TransitionBundle : inputMap InputMap, knownTransitions {OpId -> ^ 1.. Transition} @mnemonic(pirate-lithium-side) data TransitionSchema : metadata {MetaType ^ ..0xff} @@ -426,20 +402,4 @@ data ValencyType : U16 @mnemonic(email-snow-safari) data VoidState : () -@mnemonic(senator-limbo-raymond) -data XChainBlindSealTxPtr : bitcoin BPCore.BlindSealTxPtr - | liquid BPCore.BlindSealTxPtr - -@mnemonic(dynamic-life-brown) -data XChainBlindSealTxid : bitcoin BPCore.BlindSealTxid - | liquid BPCore.BlindSealTxid - -@mnemonic(alex-griffin-left) -data XChainSecretSeal : bitcoin BPCore.SecretSeal - | liquid BPCore.SecretSeal - -@mnemonic(liquid-river-absorb) -data XChainTxid : bitcoin Bitcoin.Txid - | liquid Bitcoin.Txid - diff --git a/stl/RGBLogic@0.1.0.sta b/stl/RGBLogic@0.1.0.sta index b84bc9fd..1ad80616 100644 --- a/stl/RGBLogic@0.1.0.sta +++ b/stl/RGBLogic@0.1.0.sta @@ -1,14 +1,14 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:mqltqlPk-O9$pYOd-BACRI70-DOMJ6cp-TFvhcK1-ibrOI9U#import-boxer-seminar +Id: stl:HffUFU0Z-oNyZXNs-O8u1dRc-Q4Z5mOo-3bqPppu-A0f5iTo#permit-helena-lorenzo Name: RGBLogic Dependencies: - RGBCommit#harvest-person-orion, - BPCore#austin-story-retro, + BPCore#symbol-tropic-grand, + RGBCommit#raymond-open-organic, Bitcoin#signal-color-cipher -Check-SHA256: 1c7df052c1790167b3a2f4748d4a8d602f3c8473195826c02efa6efc43b7f396 +Check-SHA256: 8d34caed4e853c7151edddfda253ec77aa3b73ceda15091820cb27240a0f5a81 -2vSEvOmAmtV*?;pC#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i<EWM?ynyZEb0ERuk6O)Q5AKbFW;J -EQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pbzY!hN5_Bp3Y36tDMM#=e#tGI($UA5U3KNx<*C>ja}LTPkk +2vSEvOmAmtV*?>@tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwEPA_P(yEWWuJg(OVXX8on}%7`W~n~ +g^Ir=cD&(=7J1!T`=A*KGYL{hLPKwDZE1A%Y!hN5_Bp3Y36tDMM#=e#tGI($UA5U3KNx<*C>ja}LTPkk Z)t7=20~CnZ*pY?00DdlT>wB!7L}MA7sFvK#<=RP4S#T1Vv-hhTICs&5fM~jaB^jIPH$voP+@X(Ze?;0 wjY>38tto&d&=e<t?OC7vzr3sh4VL=aEO-K69^0oRAF#(Wpq$-Z*OK3#8XmcC%Z%?j5}xa%));D{NyLM &t4DxfsZeKd)RyrRAF#(Wpq$sbZAg=Z*OKeKVmL%Q_{#Gkvz+H9iKg9-*)mSRaq_gMnjYqO>G4cRAF#( @@ -20,19 +20,20 @@ Mp|h<azh8d{~gylbAe9D2TWyQW>#f#{Gz8SzLEaTf~c{WkYggkPIjuQHS#3Ua|L6d7%qre2Ut&TY<W;? 2~tNwLvL+uX><etG*S<)6P6lYy(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(14peesZgXjLX>V>+d2nT9bsj>g 6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez^MR;^&ZgXjGZd7@2WqHKdNeFB<hn1p9Ku6w`$a6m4<J5>= iRT*14O40w5C%+Pd1Z1jmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<1W#~DWCZ{SL}Fu5a&K>D -1OfpDbYXCEWpn@q0RmPN*4NaBbD49mT$3z|G4nQgoFBhHh%l@K06L}1!AK9bADBNH?W>M^%H|xc>sh|D -n*!v8^Ea7rh?dzC2n+%RZ*X#DbN~eb0#*~&*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3ONJmc3T+rxD -K6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mkCE~Z(?C=PjX}i0tIhyPjX}d{&9|4h)I8ST&b@+9Xb<D$!gQg -<=j02@g_X$Ayc^T18HP<00067PjF9iWCQ~M2WMq&WpinB0000131xV6Wo~n6Z*Bkv1P6C%bZ%vHa{+R@ -LdY0XT`|v$|M|2EBF6^D+OST}`A!+zFZPFTn&AR;c>*9;C#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9 -#i?X<9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZti*Z*F5{000OCZ*Xa30w7l>toMja192_(UwD?W -=?zm*&IhOn$k(lG-qz;Dsg=m)dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#s3O)a$#<BX>@6CZU6=Z -2X|?7Ze??G0dl)S$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;R1Ad0w7l>toMja192_(UwD?W=?zm* -&IhOn$k(lG-qz;DsWeg#t`n9TUcD*&5hFi^PVx{q1b@^7zTcrn*%qZTXa#O>ZewKt00;zcaA{-$AXg`> -_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<3Rh`# -Ze??GPjX}g0{{qNa${&|c4cG$00036ZE0?0WB>&L0bJY;BNZ=sBHM?<`J6+Fr=A<oEJ!(G_IUTS%E$nK -5&{WyWo~p~bZK^F0000AS7~%^Wpi^-Z*v9%25ez@WpXhBAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c -*5<{jdBoUB2y8Zom7+;NN8Xgkb3WeV)QDb*=NiflQ)(Iz254nzXJ~W)00aqiX>Db5bYX39002k +1OfpDbYXCEWpn@q0Rka#tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwEPdYADBNH?W>M^%H|xc>sh|D +n*!v8^Ea7rh?dzC2n+%RZ*X#DbN~eb0wHj#q4l6D4ZcK)2hLYH81C&KXiWu&flb+s{C0G-{6|jDT+rxD +K6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mkCE~Z(?C=PjX}i0tIhyPjX}dBrRR>2@<s5`v}Lk@RZr<uqva| +C}IhrJ-9QY@r${f18HP<00067PjF9iWCQ~M2WMq&WpinB0000131xV6Wo~n6Z*Bkv1P6C%bZ%vHa{-G` +w{Qb%c9}kxS14ZbiR`8eq|(0z@s#80B}u>LcryZYc><q+XiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G +2{UAM9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZti*Z*F5{000OCZ*Xa30-u0rOVXX8on}%7`W~n~ +g^Ir=cD&(=7J1!T`=A*KGnL5ZdLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#s3O)a$#<BX>@6CZU6=Z +2X|?7Ze??G0gF(#a06?0nLd|SC|>c2?4}E((!U1rl;i3pNx$ZJGXivZ0-u0rOVXX8on}%7`W~n~g^Ir= +cD&(=7J1!T`=A*KGc-~Ut`n9TUcD*&5hFi^PVx{q1b@^7zTcrn*%qZTXa#O>ZewKt00;zcaA{-$pMYpf +(w(85W>N<F9;iKqioYdxyy1!#dEHw3pcx4>mB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<3Rh`# +Ze??GPjX}g1ONwVXKrtDWn=&V009VLa${&|c4cG$00067ZE0?0WB>&L0bJY;BNZ=sBHM?<`J6+Fr=A<o +EJ!(G_IUTS%E$nK5(5czWo~p~bZK^F0000AS7~%^Wpi^-Z*v9%25ez@WpXhBpMYpf(w(85W>N<F9;iKq +ioYdxyy1!#dEHw3pcx4>dBoUB2y8Zom7+;NN8Xgkb3WeV)QDb*=NiflQ)(Iz254nzXJ~W)00aqiX>Db5 +bYX39002k -----END STRICT TYPE LIB----- diff --git a/stl/RGBLogic@0.1.0.stl b/stl/RGBLogic@0.1.0.stl index 24ed32dc..2fdb92b3 100644 Binary files a/stl/RGBLogic@0.1.0.stl and b/stl/RGBLogic@0.1.0.stl differ diff --git a/stl/RGBLogic@0.1.0.sty b/stl/RGBLogic@0.1.0.sty index 9d370b08..89df3e38 100644 --- a/stl/RGBLogic@0.1.0.sty +++ b/stl/RGBLogic@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:mqltqlPk-O9$pYOd-BACRI70-DOMJ6cp-TFvhcK1-ibrOI9U#import-boxer-seminar + Id: stl:HffUFU0Z-oNyZXNs-O8u1dRc-Q4Z5mOo-3bqPppu-A0f5iTo#permit-helena-lorenzo Name: RGBLogic Version: 0.1.0 Description: Consensus logic layer for RGB smart contracts @@ -11,19 +11,19 @@ @context typelib RGBLogic -import RGBCommit#harvest-person-orion - use TransitionType#picture-reflex-brigade - use ExtensionType#apropos-scoop-viva - use Layer1#camilla-basket-justin - use OpId#picnic-single-gloria - -import BPCore#austin-story-retro +import BPCore#symbol-tropic-grand use TapretNodePartner#roger-member-educate use TapretProof#marco-border-sample use TapretPathProof#kiwi-mirror-paris use TapretRightBranch#miracle-patriot-touch use OpretProof#good-village-flex +import RGBCommit#raymond-open-organic + use TransitionType#picture-reflex-brigade + use ExtensionType#apropos-scoop-viva + use Layer1#camilla-basket-justin + use OpId#picnic-single-gloria + import Bitcoin#signal-color-cipher use ScriptBytes#equator-cockpit-gong use TapNodeHash#paprika-amanda-hunter @@ -51,8 +51,9 @@ data OpOrd : genesis () , nonce U64 , opid RGBCommit.OpId) -@mnemonic(orange-john-cyclone) -data WitnessOrd : archived () +@mnemonic(turtle-amadeus-hawaii) +data WitnessOrd : ignored () + | archived () | mined WitnessPos | tentative () diff --git a/stl/Transition.vesper b/stl/Transition.vesper index a612053c..80a7fa49 100644 --- a/stl/Transition.vesper +++ b/stl/Transition.vesper @@ -19,9 +19,7 @@ OpCommitment rec schemaId bytes len=32 aka=SchemaId timestamp is I64 issuer bytes len=32 aka=StrictHash - testnet enum Bool false=0 true=1 - altLayers1 bytes len=32 aka=StrictHash - assetTags bytes len=32 aka=StrictHash + chainNet enum ChainNet bitcoinMainnet=0 bitcoinTestnet3=1 bitcoinTestnet4=2 bitcoinSignet=3 bitcoinRegtest=4 liquidMainnet=5 liquidTestnet=6 transition tuple tag=1 _ bytes len=32 aka=ContractId _ is U16 aka=TransitionType @@ -62,165 +60,97 @@ Transition rec declarative list len=0..MAX16 wrapped tag=0 AssignVoidStateBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state is Unit aka=VoidState lock bytes len=2 aka=ReservedBytes2 fungible list len=0..MAX16 wrapped tag=1 AssignRevealedValueBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment + value union FungibleState + bits64 is U64 wrapped tag=0 + concealedDummy is Unit lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment + value union FungibleState + bits64 is U64 wrapped tag=0 + concealedDummy is Unit lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec RevealedFungible value union FungibleState bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec RevealedFungible value union FungibleState bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag lock bytes len=2 aka=ReservedBytes2 structured list len=0..MAX16 wrapped tag=2 AssignRevealedDataBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state bytes len=32 aka=ConcealedData lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state bytes len=32 aka=ConcealedData lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec RevealedData value bytes len=0..MAX16 aka=DataState salt is U128 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec RevealedData value bytes len=0..MAX16 aka=DataState salt is U128 @@ -228,33 +158,20 @@ Transition rec attachment list len=0..MAX16 wrapped tag=3 AssignRevealedAttachBlindSealTxPtr union confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state bytes len=32 aka=ConcealedAttach lock bytes len=2 aka=ReservedBytes2 confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state bytes len=32 aka=ConcealedAttach lock bytes len=2 aka=ReservedBytes2 confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 + seal bytes len=32 aka=SecretSeal state rec RevealedAttach file rec AttachState id bytes len=32 aka=AttachId @@ -262,21 +179,12 @@ Transition rec salt is U64 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 + seal rec BlindSealTxPtr + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 state rec RevealedAttach file rec AttachState id bytes len=32 aka=AttachId