diff --git a/Cargo.lock b/Cargo.lock index 7f1f6481..ca969777 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,7 @@ dependencies = [ "amplify_num", "amplify_syn", "ascii", + "rand", "serde", "serde_json", "serde_yaml", diff --git a/Cargo.toml b/Cargo.toml index 41de31c2..c7cdd2b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ name = "rgbcore-stl" required-features = ["stl"] [dependencies] -amplify = "~4.5.0" +amplify = { version = "~4.5.0", features = ["rand"] } strict_encoding = "~2.6.1" strict_types = "~1.6.3" aluvm = { version = "~0.10.6", features = ["std"] } diff --git a/src/contract/fungible.rs b/src/contract/fungible.rs index 8bd79005..351e3831 100644 --- a/src/contract/fungible.rs +++ b/src/contract/fungible.rs @@ -38,13 +38,13 @@ use core::str::FromStr; use std::io; use std::io::Write; -use amplify::hex::{Error, FromHex, ToHex}; +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 commit_verify::{ - CommitEncode, CommitVerify, CommitmentProtocol, Conceal, Digest, Sha256, UntaggedProtocol, + CommitEncode, CommitVerify, CommitmentProtocol, Conceal, DigestExt, Sha256, UntaggedProtocol, }; use secp256k1_zkp::rand::{Rng, RngCore}; use secp256k1_zkp::SECP256K1; @@ -54,7 +54,9 @@ use strict_encoding::{ }; use super::{ConfidentialState, ExposedState}; -use crate::{schema, StateCommitment, StateData, StateType, LIB_NAME_RGB}; +use crate::{ + schema, AssignmentType, ContractId, StateCommitment, StateData, StateType, LIB_NAME_RGB, +}; /// An atom of an additive state, which thus can be monomorphically encrypted. #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)] @@ -105,18 +107,39 @@ 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)] +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] #[display(Self::to_hex)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), - serde(crate = "serde_crate", from = "secp256k1_zkp::SecretKey") + serde(crate = "serde_crate", try_from = "secp256k1_zkp::SecretKey") )] pub struct BlindingFactor(Bytes32); @@ -129,17 +152,12 @@ impl ToHex for BlindingFactor { fn to_hex(&self) -> String { self.0.to_hex() } } -impl FromHex for BlindingFactor { - fn from_hex(s: &str) -> Result { Bytes32::from_hex(s).map(Self) } - fn from_byte_iter(_: I) -> Result - where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { - unreachable!() - } -} - impl FromStr for BlindingFactor { - type Err = hex::Error; - fn from_str(s: &str) -> Result { Self::from_hex(s) } + type Err = BlindingParseError; + fn from_str(s: &str) -> Result { + let bytes = Bytes32::from_str(s)?; + Self::try_from(bytes).map_err(BlindingParseError::from) + } } impl From for BlindingFactor { @@ -147,28 +165,70 @@ impl From for BlindingFactor { } impl From for secp256k1_zkp::SecretKey { - fn from(bf: BlindingFactor) -> Self { - secp256k1_zkp::SecretKey::from_slice(bf.0.as_inner()) + 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(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 any subset of the negatives or positives are inverses of other + /// negatives or positives, or if the balancing factor is zero (sum of + /// negatives already equal to the sum of positives). + pub fn zero_balanced( + negative: impl IntoIterator, + positive: impl IntoIterator, + ) -> Result { + 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") } } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -/// value provided for a blinding factor overflows prime field order for -/// Secp256k1 curve. -pub struct FieldOrderOverflow; - impl TryFrom<[u8; 32]> for BlindingFactor { - type Error = FieldOrderOverflow; + type Error = InvalidFieldElement; fn try_from(array: [u8; 32]) -> Result { secp256k1_zkp::SecretKey::from_slice(&array) - .map_err(|_| FieldOrderOverflow) + .map_err(|_| InvalidFieldElement) .map(Self::from) } } +impl TryFrom for BlindingFactor { + type Error = InvalidFieldElement; + + fn try_from(bytes: Bytes32) -> Result { + Self::try_from(bytes.to_byte_array()) + } +} + /// State item for a homomorphically-encryptable state. /// /// Consists of the 64-bit value and @@ -182,23 +242,48 @@ pub struct RevealedValue { /// Blinding factor used in Pedersen commitment pub blinding: BlindingFactor, + + /// Asset-specific tag preventing mixing assets of different type. + pub asset_tag: Bytes32, } impl RevealedValue { + /// Constructs new state using the provided value using random blinding + /// factor. + pub fn new_random_blinding( + value: impl Into, + contract_id: ContractId, + assignment_type: AssignmentType, + ) -> Self { + Self::with_blinding(value, BlindingFactor::random(), contract_id, assignment_type) + } + /// Constructs new state using the provided value and random generator for /// creating blinding factor. - pub fn new(value: impl Into, rng: &mut R) -> Self { - Self { - value: value.into(), - blinding: BlindingFactor::from(secp256k1_zkp::SecretKey::new(rng)), - } + pub fn with_random_blinding( + value: impl Into, + rng: &mut R, + contract_id: ContractId, + assignment_type: AssignmentType, + ) -> Self { + Self::with_blinding(value, BlindingFactor::random_custom(rng), contract_id, assignment_type) } /// Convenience constructor. - pub fn with(value: impl Into, blinding: impl Into) -> Self { + pub fn with_blinding( + value: impl Into, + blinding: BlindingFactor, + contract_id: ContractId, + assignment_type: AssignmentType, + ) -> Self { + let mut engine = Sha256::default(); + engine.input_raw(&contract_id.to_byte_array()); + engine.input_raw(&assignment_type.to_le_bytes()); + let asset_tag = engine.finish().into(); Self { value: value.into(), - blinding: blinding.into(), + blinding, + asset_tag, } } } @@ -286,12 +371,7 @@ impl CommitVerify for PedersenCommitment { .expect("type guarantees of BlindingFactor are broken"); let FungibleState::Bits64(value) = revealed.value; - // TODO: Check that we create correct generator value. - let one_key = secp256k1_zkp::SecretKey::from_slice(&secp256k1_zkp::constants::ONE) - .expect("secret key from a constant"); - let g = secp256k1_zkp::PublicKey::from_secret_key(SECP256K1, &one_key); - let h: [u8; 32] = Sha256::digest(g.serialize_uncompressed()).into(); - let tag = Tag::from(h); + let tag = Tag::from(revealed.asset_tag.to_byte_array()); let generator = Generator::new_unblinded(SECP256K1, tag); secp256k1_zkp::PedersenCommitment::new(SECP256K1, value, blinding, generator).into() @@ -420,11 +500,15 @@ impl ConcealedValue { mod test { use std::collections::HashSet; + use amplify::ByteArray; + use super::*; #[test] fn commitments_determinism() { - let value = RevealedValue::new(15, &mut thread_rng()); + let tag: ContractId = ContractId::from_byte_array([1u8; 32]); + + let value = RevealedValue::with_random_blinding(15, &mut thread_rng(), tag, 0); let generators = (0..10) .map(|_| { @@ -435,4 +519,114 @@ mod test { .collect::>(); assert_eq!(generators.len(), 1); } + + #[test] + fn pedersen_blinding_mismatch() { + let mut r = thread_rng(); + let tag: ContractId = ContractId::from_byte_array([1u8; 32]); + + let a = + PedersenCommitment::commit(&RevealedValue::with_random_blinding(15, &mut r, tag, 0)) + .into_inner(); + let b = PedersenCommitment::commit(&RevealedValue::with_random_blinding(7, &mut r, tag, 0)) + .into_inner(); + + let c = + PedersenCommitment::commit(&RevealedValue::with_random_blinding(13, &mut r, tag, 0)) + .into_inner(); + let d = PedersenCommitment::commit(&RevealedValue::with_random_blinding(9, &mut r, tag, 0)) + .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: ContractId = ContractId::from_byte_array([1u8; 32]); + + let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag, 0)) + .into_inner(); + let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag, 0)) + .into_inner(); + + let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag, 0)) + .into_inner(); + let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag, 0)) + .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: ContractId = ContractId::from_byte_array([1u8; 32]); + let tag2: ContractId = ContractId::from_byte_array([2u8; 32]); + + let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag2, 0)) + .into_inner(); + let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag, 0)) + .into_inner(); + + let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag2, 0)) + .into_inner(); + let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag, 0)) + .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: ContractId = ContractId::from_byte_array([1u8; 32]); + let tag2: ContractId = ContractId::from_byte_array([2u8; 32]); + + let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag2, 0)) + .into_inner(); + let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag2, 0)) + .into_inner(); + let c = PedersenCommitment::commit(&RevealedValue::with_blinding(2, blinding, tag, 0)) + .into_inner(); + let d = PedersenCommitment::commit(&RevealedValue::with_blinding(4, blinding, tag, 0)) + .into_inner(); + + let e = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag2, 0)) + .into_inner(); + let f = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag2, 0)) + .into_inner(); + let g = PedersenCommitment::commit(&RevealedValue::with_blinding(1, blinding, tag, 0)) + .into_inner(); + let h = PedersenCommitment::commit(&RevealedValue::with_blinding(5, blinding, tag, 0)) + .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: ContractId = ContractId::from_byte_array([1u8; 32]); + + let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding1, tag, 0)) + .into_inner(); + let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding2, tag, 0)) + .into_inner(); + + let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding3, tag, 0)) + .into_inner(); + let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding4, tag, 0)) + .into_inner(); + + assert!(secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) + } } diff --git a/src/contract/mod.rs b/src/contract/mod.rs index 687b2279..2b663b3d 100644 --- a/src/contract/mod.rs +++ b/src/contract/mod.rs @@ -48,8 +48,8 @@ pub use contract::{ }; pub use data::{ConcealedData, RevealedData, VoidState}; pub use fungible::{ - BlindingFactor, ConcealedValue, FieldOrderOverflow, FungibleState, NoiseDumb, - PedersenCommitment, RangeProof, RangeProofError, RevealedValue, + BlindingFactor, BlindingParseError, ConcealedValue, FungibleState, InvalidFieldElement, + NoiseDumb, PedersenCommitment, RangeProof, RangeProofError, RevealedValue, }; pub use global::{GlobalState, GlobalValues}; pub use operations::{ diff --git a/src/stl.rs b/src/stl.rs index 18889367..7fb3c4d7 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -32,7 +32,7 @@ use crate::{AnchoredBundle, Extension, Genesis, SubSchema, LIB_NAME_RGB}; /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB: &str = - "urn:ubideco:stl:DmN8aZj1dPvAvx5JYfz22azHs5RRbECxmxWoo5LK7E5f#house-herman-poem"; + "urn:ubideco:stl:AjePbbRf34u9Vx4iN8uyPZSaS5XC4jnTDpvMDePnerd1#medusa-boris-virtual"; fn _rgb_core_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB), tiny_bset! { diff --git a/src/validation/model.rs b/src/validation/model.rs index 49da1897..ffa664d6 100644 --- a/src/validation/model.rs +++ b/src/validation/model.rs @@ -29,9 +29,9 @@ use strict_types::SemId; use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{ConsignmentApi, VirtualMachine}; use crate::{ - validation, Assignments, AssignmentsRef, ExposedSeal, GlobalState, GlobalStateSchema, - GlobalValues, GraphSeal, Inputs, OpFullType, OpId, OpRef, Operation, Opout, Redeemed, Schema, - SchemaRoot, TypedAssigns, Valencies, BLANK_TRANSITION_ID, + validation, Assignments, AssignmentsRef, ContractId, ExposedSeal, GlobalState, + GlobalStateSchema, GlobalValues, GraphSeal, Inputs, OpFullType, OpId, OpRef, Operation, Opout, + Redeemed, Schema, SchemaRoot, TypedAssigns, Valencies, BLANK_TRANSITION_ID, }; impl Schema { @@ -165,7 +165,14 @@ impl Schema { status += self.validate_valencies(id, op.valencies(), valency_schema); - let op_info = OpInfo::with(id, self.subset_of.is_some(), &op, &prev_state, &redeemed); + let op_info = OpInfo::with( + consignment.genesis().contract_id(), + id, + self.subset_of.is_some(), + &op, + &prev_state, + &redeemed, + ); // We need to run scripts as the very last step, since before that // we need to make sure that the operation data match the schema, so @@ -421,6 +428,7 @@ impl Schema { pub struct OpInfo<'op> { pub subschema: bool, + pub contract_id: ContractId, pub id: OpId, pub ty: OpFullType, pub metadata: &'op SmallBlob, @@ -433,6 +441,7 @@ pub struct OpInfo<'op> { impl<'op> OpInfo<'op> { pub fn with( + contract_id: ContractId, id: OpId, subschema: bool, op: &'op OpRef<'op>, @@ -442,6 +451,7 @@ impl<'op> OpInfo<'op> { OpInfo { id, subschema, + contract_id, ty: op.full_type(), metadata: op.metadata(), prev_state, diff --git a/src/validation/validator.rs b/src/validation/validator.rs index ff9f1d82..644ac196 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -502,14 +502,11 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveTx> } // [VALIDATION]: Checking anchor deterministic bitcoin commitment - match anchor.verify(self.contract_id, message, &witness.tx) { - Err(err) => { - // The operation is not committed to bitcoin transaction graph! - // Ultimate failure. But continuing to detect the rest (after reporting it). - self.status - .add_failure(Failure::AnchorInvalid(opid, txid, err)); - } - _ => {} + if let Err(err) = anchor.verify(self.contract_id, message, &witness.tx) { + // The operation is not committed to bitcoin transaction graph! + // Ultimate failure. But continuing to detect the rest (after reporting it). + self.status + .add_failure(Failure::AnchorInvalid(opid, txid, err)); } } } diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index 8767ac0b..3d4d57ae 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -31,11 +31,12 @@ use aluvm::library::{CodeEofError, LibSite, Read, Write}; use aluvm::reg::{CoreRegs, Reg16, RegA, RegS}; use amplify::num::u4; use amplify::Wrapper; +use commit_verify::Conceal; use strict_encoding::StrictSerialize; use super::opcodes::*; use crate::validation::OpInfo; -use crate::{Assign, TypedAssigns}; +use crate::{Assign, RevealedValue, TypedAssigns}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] pub enum ContractOp { @@ -127,13 +128,28 @@ pub enum ContractOp { /// to `false`. #[display("pcvs {0}")] PcVs(u16), - /* - /// Verifies corrected sum of pedersen commitments adding a value taken from `RegR` to the list - /// of inputs (negatives). - PcCs(u16, RegR), - */ + + /// Verifies equivalence of a sum of pedersen commitments for the list of + /// outputs with a given owned state type against a value taken from a + /// global state. + /// + /// The first argument specifies owned state type for the sum operation. If + /// this state does not exist, either inputs or outputs do not have + /// any data for the state, or the state is not + /// of `FungibleState::Bits64`, the verification fails. + /// + /// The second argument specifies global state type. If the state does not + /// exist, there is more than one value, or it is not a u64 value, the + /// verification fails. + /// + /// If verification succeeds, doesn't change `st0` value; otherwise sets it + /// to `false`. + #[display("pccs {0},{1}")] + PcCs(/** owned state type */ u16, /** global state type */ u16), + /// All other future unsupported operations, which must set `st0` to /// `false`. + #[display("fail {0}")] Fail(u8), } @@ -149,6 +165,42 @@ impl InstructionSet for ContractOp { return ExecStep::Stop; }}; } + macro_rules! load_inputs { + ($state_type:ident) => {{ + if !context.prev_state.contains_key($state_type) { + return ExecStep::Next; + } + let Some(prev_state) = context.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::>(), + _ => fail!(), + } + }}; + } + macro_rules! load_outputs { + ($state_type:ident) => {{ + if !context.owned_state.has_type(*$state_type) { + return ExecStep::Next; + } + let Some(new_state) = context.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::>(), + _ => fail!(), + } + }}; + } match self { ContractOp::CnP(state_type, reg) => { @@ -225,35 +277,36 @@ impl InstructionSet for ContractOp { } ContractOp::PcVs(state_type) => { - if !context.prev_state.contains_key(state_type) && - !context.owned_state.has_type(*state_type) - { - return ExecStep::Next; + 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, + ) { + fail!() } + } - let Some(prev_state) = context.prev_state.get(state_type) else { + ContractOp::PcCs(owned_state, global_state) => { + let Some(sum) = context.global.get(global_state) else { fail!() }; - let Some(new_state) = context.owned_state.get(*state_type) else { + if sum.len() != 1 { fail!() - }; + } + if sum[0].as_inner().len() != 8 { + fail!() + } + let mut bytes = [0u8; 8]; + bytes.copy_from_slice(sum[0].as_inner()); + let sum = u64::from_le_bytes(bytes); - let inputs = match prev_state { - TypedAssigns::Fungible(state) => state - .iter() - .map(Assign::to_confidential_state) - .map(|s| s.commitment.into_inner()) - .collect::>(), - _ => fail!(), - }; - let outputs = match new_state { - TypedAssigns::Fungible(state) => state - .iter() - .map(Assign::to_confidential_state) - .map(|s| s.commitment.into_inner()) - .collect::>(), - _ => fail!(), - }; + let sum = + RevealedValue::with_blinding(sum, zero!(), context.contract_id, *owned_state); + + let inputs = [sum.conceal().commitment.into()]; + let outputs = load_outputs!(owned_state); if !secp256k1_zkp::verify_commitments_sum_to_equal( secp256k1_zkp::SECP256K1, @@ -287,6 +340,7 @@ impl Bytecode for ContractOp { ContractOp::LdM(_) => 1, ContractOp::PcVs(_) => 2, + ContractOp::PcCs(_, _) => 4, ContractOp::Fail(_) => 0, } @@ -309,6 +363,7 @@ impl Bytecode for ContractOp { ContractOp::LdM(_) => INSTR_LDM, ContractOp::PcVs(_) => INSTR_PCVS, + ContractOp::PcCs(_, _) => INSTR_PCCS, ContractOp::Fail(other) => *other, } @@ -373,6 +428,10 @@ impl Bytecode for ContractOp { } ContractOp::PcVs(state_type) => writer.write_u16(*state_type)?, + ContractOp::PcCs(owned_type, global_type) => { + writer.write_u16(*owned_type)?; + writer.write_u16(*global_type)?; + } ContractOp::Fail(_) => {} } @@ -438,6 +497,7 @@ impl Bytecode for ContractOp { } INSTR_PCVS => Self::PcVs(reader.read_u16()?), + INSTR_PCCS => Self::PcCs(reader.read_u16()?, reader.read_u16()?), x => Self::Fail(x), }) diff --git a/stl/RGB@0.1.0.sta b/stl/RGB@0.1.0.sta index 380038fe..aed109c7 100644 --- a/stl/RGB@0.1.0.sta +++ b/stl/RGB@0.1.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:DmN8aZj1dPvAvx5JYfz22azHs5RRbECxmxWoo5LK7E5f +Id: urn:ubideco:stl:AjePbbRf34u9Vx4iN8uyPZSaS5XC4jnTDpvMDePnerd1 Name: RGB Dependencies: urn:ubideco:stl:ZtHaBzu9ojbDahaGKEXe5v9DfSDxLERbLkEB23R6Q6V, @@ -60,8 +60,8 @@ AAAA//8AAAAAAAAGQW5jaG9yBAIAB2JpdGNvaW4ABQECFwZOaYm8ANN+QATAdalw 1SQOh8fRNH4sG25uxi7AoTfh0W5XqD5OSJpAa5BMLe+pMQAZmEa0NmHOOFai1y4a agEGbGlxdWlkAAUBAhcGTmmJvADTfkAEwHWpcNUkDofH0TR+LBtubsYuwKE34dFu V6g+TkiaQGuQTC3vqTEAGZhGtDZhzjhWotcuGmoOQW5jaG9yZWRCdW5kbGUGAgZh -bmNob3IBdb3qhJMVeLEhjGiDlgRn3guHZg12SkTX/5sPXSEWsT4GYnVuZGxlAeLY -yqPJCUdMB3aQUXhN2onJPBUjFToCB5YGb/OPLggzIkFzc2lnblJldmVhbGVkQXR0 +bmNob3IBdb3qhJMVeLEhjGiDlgRn3guHZg12SkTX/5sPXSEWsT4GYnVuZGxlAf5n +2T0zSneteAbZf+2S7ggs4i6yNFaIGy4tZBwGk1RJIkFzc2lnblJldmVhbGVkQXR0 YWNoQmxpbmRTZWFsVHhQdHIEBAAMY29uZmlkZW50aWFsAAYCBHNlYWwCFwZOaYm8 ANN+QATAdalw1SQOh8fRNH4sG25uxi7AoTdoGeu81bMYq5ezmKVLNmXd2qcGb+jp JOcDYKmUs70GTgVzdGF0ZQH8NEXdX88NC/+sFaR6ugUi4FuLKxswZVKHg497LeuO @@ -109,9 +109,9 @@ Tl0BEWNvbmZpZGVudGlhbFN0YXRlAAYCBHNlYWwBTA5mElZhWYYrAaikUtKPFKCF um5wG6hAPcxiD+J2regFc3RhdGUBwlGtZel1DayaElnMwIUkXNX3sW9S2HI2Rizx dYyfTl0CEGNvbmZpZGVudGlhbFNlYWwABgIEc2VhbAIXBk5pibwA035ABMB1qXDV JA6Hx9E0fiwbbm7GLsChN2gZ67zVsxirl7OYpUs2Zd3apwZv6Okk5wNgqZSzvQZO -BXN0YXRlAezPeoecH61vOHwe0niJwOD9tN7UOjKTHOwsy6y70qwtAwhyZXZlYWxl +BXN0YXRlAbjwU4MuqTuHtnIA5H8aePDGVZlPIyG9ZOE72dEvdzA2AwhyZXZlYWxl ZAAGAgRzZWFsAUwOZhJWYVmGKwGopFLSjxSghbpucBuoQD3MYg/idq3oBXN0YXRl -AezPeoecH61vOHwe0niJwOD9tN7UOjKTHOwsy6y70qwtIEFzc2lnblJldmVhbGVk +AbjwU4MuqTuHtnIA5H8aePDGVZlPIyG9ZOE72dEvdzA2IEFzc2lnblJldmVhbGVk VmFsdWVCbGluZFNlYWxUeGlkBAQADGNvbmZpZGVudGlhbAAGAgRzZWFsAhcGTmmJ vADTfkAEwHWpcNUkDofH0TR+LBtubsYuwKE3aBnrvNWzGKuXs5ilSzZl3dqnBm/o 6STnA2CplLO9Bk4Fc3RhdGUBwlGtZel1DayaElnMwIUkXNX3sW9S2HI2RizxdYyf @@ -119,9 +119,9 @@ Tl0BEWNvbmZpZGVudGlhbFN0YXRlAAYCBHNlYWwBIiginEN2PcizQprhAmty41DZ dy9s4y6MKYoFX2dX8iUFc3RhdGUBwlGtZel1DayaElnMwIUkXNX3sW9S2HI2Rizx dYyfTl0CEGNvbmZpZGVudGlhbFNlYWwABgIEc2VhbAIXBk5pibwA035ABMB1qXDV JA6Hx9E0fiwbbm7GLsChN2gZ67zVsxirl7OYpUs2Zd3apwZv6Okk5wNgqZSzvQZO -BXN0YXRlAezPeoecH61vOHwe0niJwOD9tN7UOjKTHOwsy6y70qwtAwhyZXZlYWxl +BXN0YXRlAbjwU4MuqTuHtnIA5H8aePDGVZlPIyG9ZOE72dEvdzA2AwhyZXZlYWxl ZAAGAgRzZWFsASIoIpxDdj3Is0Ka4QJrcuNQ2XcvbOMujCmKBV9nV/IlBXN0YXRl -AezPeoecH61vOHwe0niJwOD9tN7UOjKTHOwsy6y70qwtHUFzc2lnblZvaWRTdGF0 +AbjwU4MuqTuHtnIA5H8aePDGVZlPIyG9ZOE72dEvdzA2HUFzc2lnblZvaWRTdGF0 ZUJsaW5kU2VhbFR4UHRyBAQADGNvbmZpZGVudGlhbAAGAgRzZWFsAhcGTmmJvADT fkAEwHWpcNUkDofH0TR+LBtubsYuwKE3aBnrvNWzGKuXs5ilSzZl3dqnBm/o6STn A2CplLO9Bk4Fc3RhdGUBLrKl/hfAMEQwmOBcmxtabNYe7XYNYd7LgCbTZPMW4bsB @@ -142,21 +142,21 @@ LBtubsYuwKE3aBnrvNWzGKuXs5ilSzZl3dqnBm/o6STnA2CplLO9Bk4Fc3RhdGUB LrKl/hfAMEQwmOBcmxtabNYe7XYNYd7LgCbTZPMW4bsDCHJldmVhbGVkAAYCBHNl YWwBIiginEN2PcizQprhAmty41DZdy9s4y6MKYoFX2dX8iUFc3RhdGUBLrKl/hfA MEQwmOBcmxtabNYe7XYNYd7LgCbTZPMW4bsZQXNzaWdubWVudHNCbGluZFNlYWxU -eFB0cgUBAAoAAAIBeeswdqBjNd1ZN9fMj16oNoJlpPYZR4/VhqpLivbl09EAAAAA -AAAAAP8AAAAAAAAAGEFzc2lnbm1lbnRzQmxpbmRTZWFsVHhpZAUBAAoAAAIBzNk8 -Xt1gPIiJeZ0mVdSnm96m8GCZCphuRngGDWMVo/IAAAAAAAAAAP8AAAAAAAAACEF0 +eFB0cgUBAAoAAAIBHFgwJQWeFLhHcXtlpwQOzSzy5fNNtE2I5wS6Iws7wEAAAAAA +AAAAAP8AAAAAAAAAGEFzc2lnbm1lbnRzQmxpbmRTZWFsVHhpZAUBAAoAAAIB+R5Z +fLOGXKWo0Y3PsJnikC8k7o3YRcN+U3Q1dTpdM7sAAAAAAAAAAP8AAAAAAAAACEF0 dGFjaElkBQEABwAAQCAADkJsaW5kaW5nRmFjdG9yBQEABwAAQCAACkJ1bmRsZUl0 ZW0GAgZpbnB1dHMACQAAAgAAAAAAAAAA/wAAAAAAAAAKdHJhbnNpdGlvbgAEAgAE -bm9uZQAAAAEEc29tZQAFAQFyav7sDLwdmsk+0zB+aqpG2Htym8Lp6ZlbxBJ+CwyV -Ew9Db25jZWFsZWRBdHRhY2gFAQAHAABAIAANQ29uY2VhbGVkRGF0YQUBAAcAAEAg +bm9uZQAAAAEEc29tZQAFAQHobcv4hus/oXG8P3t2avrn0h9dq3efkXyh5w/AbbJ2 +GQ9Db25jZWFsZWRBdHRhY2gFAQAHAABAIAANQ29uY2VhbGVkRGF0YQUBAAcAAEAg ABFDb25jZWFsZWRGdW5naWJsZQYCCmNvbW1pdG1lbnQBSL0abhf7hjsWfH4lXjVn 24JD7ypeuuuixQrNCa6eURoKcmFuZ2VQcm9vZgGoWGv4kWXawiMQbb2FxIbJN+aw ZusMZkH/Fi9oqHelmApDb250cmFjdElkBQEABwAAQCAACUV4dGVuc2lvbgYIA2Zm dgHam1ETWBZWdpCH+5nlVpRyNoDXOQwGocwkmCwFZPfM1Qpjb250cmFjdElkAZ8I LEk6yAKiusXd3AsifCCvlNRoxEjPGloh4L3C9ToyDWV4dGVuc2lvblR5cGUAAAII bWV0YWRhdGEACAAAQAAAAAAAAAAA//8AAAAAAAAHZ2xvYmFscwHrb4qQ9rjFeSME -Vkq8MvZ8eOBQhTqmCJ4MTh0+15BXlQthc3NpZ25tZW50cwFoIrLyWVFI4r0yCsDT -PMMWyycifg2ukzKHdgJy6UTDCwhyZWRlZW1lZAGBBPQMEHyCLedbjLifPUq6TmRt +Vkq8MvZ8eOBQhTqmCJ4MTh0+15BXlQthc3NpZ25tZW50cwGw8ILr12tYO2Ka8sID +wIi86YDMOHuJDq3YUxs4peSsJQhyZWRlZW1lZAGBBPQMEHyCLedbjLifPUq6TmRt GcTdOVSe/wWDcQNhogl2YWxlbmNpZXMBsOCFp4c28gbxzK8xWHgGA4mJ7+JRPBb8 ZFKSUw/EB38PRXh0ZW5zaW9uU2NoZW1hBgUIbWV0YWRhdGECQzQDlNgbMOJSKJAm HvNv+fioOVGR9QtpXiMqHrO3QchrBKMUnqaVABZnn+8CtKsk9ea3imTI2dC9ZfzX @@ -171,8 +171,8 @@ fTE//P4A+l0kelQEkBAFY2hhaW4CTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17v gnZyd1dS2isFLayiTrJNkcIhfaCRfc9eTfyHZJ8nodoZFEUJkwlhbHRMYXllcjEB JFdS2GWA8JzKaiM3VBJEIGB8oyx/7szxFBAAbwoJKowIbWV0YWRhdGEACAAAQAAA AAAAAAAA//8AAAAAAAAHZ2xvYmFscwHrb4qQ9rjFeSMEVkq8MvZ8eOBQhTqmCJ4M -Th0+15BXlQthc3NpZ25tZW50cwFoIrLyWVFI4r0yCsDTPMMWyycifg2ukzKHdgJy -6UTDCwl2YWxlbmNpZXMBsOCFp4c28gbxzK8xWHgGA4mJ7+JRPBb8ZFKSUw/EB38N +Th0+15BXlQthc3NpZ25tZW50cwGw8ILr12tYO2Ka8sIDwIi86YDMOHuJDq3YUxs4 +peSsJQl2YWxlbmNpZXMBsOCFp4c28gbxzK8xWHgGA4mJ7+JRPBb8ZFKSUw/EB38N R2VuZXNpc1NjaGVtYQYECG1ldGFkYXRhAkM0A5TYGzDiUiiQJh7zb/n4qDlRkfUL aV4jKh6zt0HIawSjFJ6mlQAWZ5/vArSrJPXmt4pkyNnQvWX816NYTo0HZ2xvYmFs cwAKAAACATbBNKH6oIETp90wgDxesPLC/doUsNWj1pPDbp4PMqp5AAAAAAAAAAD/ @@ -195,74 +195,74 @@ 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 -U3RhdGUFAQAAAA== +uPgru/Skpg2zvz9FuA+UbniDw61SbZP0b6MBqG5H2ghhc3NldFRhZwAHAABAIAAG +U2NoZW1hBgoDZmZ2AdqbURNYFlZ2kIf7meVWlHI2gNc5DAahzCSYLAVk98zVCHN1 +YnNldE9mAAQCAARub25lAAAAAQRzb21lAAUBAAAAC2dsb2JhbFR5cGVzAAoAAAIB +x5im2GM2eEQe2lFuLD6Lvw6osEqAwbcduely5j9x5iQAAAAAAAAAAP8AAAAAAAAA +Cm93bmVkVHlwZXMACgAAAgE4yhTghSLH4zmCRpSyw5lYdVOm6MoMDuHolYm6iXcb +8wAAAAAAAAAA/wAAAAAAAAAMdmFsZW5jeVR5cGVzAAkAAAIAAAAAAAAAAP8AAAAA +AAAAB2dlbmVzaXMBm5QN7zOQn58O7smhw3YQQhn+ZLZIpBLAOnSvAEKc6OQKZXh0 +ZW5zaW9ucwAKAAACASOei7XZDLpQUzMkAyGW+6Qj8vPze9UGFZPgE1iWMcr7AAAA +AAAAAAD/AAAAAAAAAAt0cmFuc2l0aW9ucwAKAAACAXXHIeCGP9woM6VBTC3sjyIx +TvYyYDEtpwTmXO3YxGdMAAAAAAAAAAD/AAAAAAAAAAp0eXBlU3lzdGVtAkM0A5TY +GzDiUiiQJh7zb/n4qDlRkfULaV4jKh6zt0HILkdbPnPJ4CJtjiwnuhSzqiW+bSj3 +R34s/YxNKF4Y7FYGc2NyaXB0AcYYY3tnTQy0vKnAQ11/MmKDmHhzdCdD0TflRPu6 +EtBMCFNjaGVtYUlkBQEABwAAQCAADFNjaGVtYVNjaGVtYQYKA2ZmdgHam1ETWBZW +dpCH+5nlVpRyNoDXOQwGocwkmCwFZPfM1QhzdWJzZXRPZgAEAgAEbm9uZQAAAAEE +c29tZQAFAQGwzkKTm4xhAgglqQno7zlFxAxDytpPPMus3NlYcGE5hQtnbG9iYWxU +eXBlcwAKAAACAceYpthjNnhEHtpRbiw+i78OqLBKgMG3HbnpcuY/ceYkAAAAAAAA +AAD/AAAAAAAAAApvd25lZFR5cGVzAAoAAAIBOMoU4IUix+M5gkaUssOZWHVTpujK +DA7h6JWJuol3G/MAAAAAAAAAAP8AAAAAAAAADHZhbGVuY3lUeXBlcwAJAAACAAAA +AAAAAAD/AAAAAAAAAAdnZW5lc2lzAZuUDe8zkJ+fDu7JocN2EEIZ/mS2SKQSwDp0 +rwBCnOjkCmV4dGVuc2lvbnMACgAAAgEjnou12Qy6UFMzJAMhlvukI/Lz83vVBhWT +4BNYljHK+wAAAAAAAAAA/wAAAAAAAAALdHJhbnNpdGlvbnMACgAAAgF1xyHghj/c +KDOlQUwt7I8iMU72MmAxLacE5lzt2MRnTAAAAAAAAAAA/wAAAAAAAAAKdHlwZVN5 +c3RlbQJDNAOU2Bsw4lIokCYe82/5+Kg5UZH1C2leIyoes7dByC5HWz5zyeAibY4s +J7oUs6olvm0o90d+LP2MTSheGOxWBnNjcmlwdAHGGGN7Z00MtLypwENdfzJig5h4 +c3QnQ9E35UT7uhLQTAZTY3JpcHQEAQAFYWx1Vm0ABQEBovrqnnBcnJHM291G7Y9w +5Y71FIM+yD5cZLVqW8NTrbAcU2VhbERlZmluaXRpb25CbGluZFNlYWxUeFB0cgQC +AAdiaXRjb2luAAUBAhcGTmmJvADTfkAEwHWpcNUkDofH0TR+LBtubsYuwKE3frX4 +M3yRqm+4vZW7u8v14cUliUXSEXbaHtTcjMUxJWUBBmxpcXVpZAAFAQIXBk5pibwA +035ABMB1qXDVJA6Hx9E0fiwbbm7GLsChN361+DN8kapvuL2Vu7vL9eHFJYlF0hF2 +2h7U3IzFMSVlG1NlYWxEZWZpbml0aW9uQmxpbmRTZWFsVHhpZAQCAAdiaXRjb2lu +AAUBAhcGTmmJvADTfkAEwHWpcNUkDofH0TR+LBtubsYuwKE3DFBskkmcWPMvLuws +VLjXFmu8mBTsPpkCRT1xLrphCeEBBmxpcXVpZAAFAQIXBk5pibwA035ABMB1qXDV +JA6Hx9E0fiwbbm7GLsChNwxQbJJJnFjzLy7sLFS41xZrvJgU7D6ZAkU9cS66YQnh +C1N0YXRlU2NoZW1hBAQAC2RlY2xhcmF0aXZlAAAAAQhmdW5naWJsZQAFAQH59KwI +Zq5Bd2bU/QwRfQSx2VT9DmdeEjtiBOtxT+nlRgIKc3RydWN0dXJlZAAFAQJDNAOU +2Bsw4lIokCYe82/5+Kg5UZH1C2leIyoes7dByGsEoxSeppUAFmef7wK0qyT15reK +ZMjZ0L1l/NejWE6NAwphdHRhY2htZW50AAUBAUIwYYWIyNSrFCZAx/3JFyzN0P8Q +/w2TgABEfIia3cx5ClRyYW5zaXRpb24GCANmZnYB2ptRE1gWVnaQh/uZ5VaUcjaA +1zkMBqHMJJgsBWT3zNUKY29udHJhY3RJZAGfCCxJOsgCorrF3dwLInwgr5TUaMRI +zxpaIeC9wvU6Mg50cmFuc2l0aW9uVHlwZQAAAghtZXRhZGF0YQAIAABAAAAAAAAA +AAD//wAAAAAAAAdnbG9iYWxzAetvipD2uMV5IwRWSrwy9nx44FCFOqYIngxOHT7X +kFeVBmlucHV0cwFaX9oXbyoy58+YADITLy6YdgaX++L/qrjVQ09cyFPGbAthc3Np +Z25tZW50cwHhSCf/avd/oVprtF1yoHrCl4cqKUoFMRqrB8fy7ke7kwl2YWxlbmNp +ZXMBsOCFp4c28gbxzK8xWHgGA4mJ7+JRPBb8ZFKSUw/EB38QVHJhbnNpdGlvbkJ1 +bmRsZQUBAAoBlcjmeh51Yl/UllVCapHrfkKQoW9amPG+UPe2iiQS98UBrPzDdM8e +b/5BEUC5w35RnmdVpWYKXp0GDnewEyG5F8AAAAAAAAAAAP8AAAAAAAAAEFRyYW5z +aXRpb25TY2hlbWEGBQhtZXRhZGF0YQJDNAOU2Bsw4lIokCYe82/5+Kg5UZH1C2le +Iyoes7dByGsEoxSeppUAFmef7wK0qyT15reKZMjZ0L1l/NejWE6NB2dsb2JhbHMA +CgAAAgE2wTSh+qCBE6fdMIA8XrDywv3aFLDVo9aTw26eDzKqeQAAAAAAAAAA/wAA +AAAAAAAGaW5wdXRzAAoAAAIBNsE0ofqggROn3TCAPF6w8sL92hSw1aPWk8Nung8y +qnkAAAAAAAAAAP8AAAAAAAAAC2Fzc2lnbm1lbnRzAAoAAAIBNsE0ofqggROn3TCA +PF6w8sL92hSw1aPWk8Nung8yqnkAAAAAAAAAAP8AAAAAAAAACXZhbGVuY2llcwAJ +AAACAAAAAAAAAAD/AAAAAAAAABpUeXBlZEFzc2lnbnNCbGluZFNlYWxUeFB0cgQE +AAtkZWNsYXJhdGl2ZQAFAQAIASlmLu7+YHlscLtafG2Pcozo6kvLU/N6TMuVk2gI +mp7uAAAAAAAAAAD//wAAAAAAAAEIZnVuZ2libGUABQEACAE/1LE1GbqEe5PP9dcp +jwEZE3D//ePM8xlRUICKuHC7iQAAAAAAAAAA//8AAAAAAAACCnN0cnVjdHVyZWQA +BQEACAFZolHNjebLiSRE7c91W7GqpdwcP9rBNM1sJTbV9hOKwgAAAAAAAAAA//8A +AAAAAAD/CmF0dGFjaG1lbnQABQEACAH7zBd2FTkXpjSm4b7gHt0r3GK/r4la5XU5 +cv8qQZfYgAAAAAAAAAAA//8AAAAAAAAZVHlwZWRBc3NpZ25zQmxpbmRTZWFsVHhp +ZAQEAAtkZWNsYXJhdGl2ZQAFAQAIAZjmCNUpvD8wzk9MqgCsLOdH/s86QuxysgqC +wL4CEwKJAAAAAAAAAAD//wAAAAAAAAEIZnVuZ2libGUABQEACAEugG8wzLKXaFZh +AHnQKXUKxcYo17vA5II0luu2P2HLgQAAAAAAAAAA//8AAAAAAAACCnN0cnVjdHVy +ZWQABQEACAE+3J1wNEPkBuDqB11Dgy/Nr1/LVPO0gJ1pu+1/YKRBowAAAAAAAAAA +//8AAAAAAAD/CmF0dGFjaG1lbnQABQEACAEP+aNjbGPkkqopcG754NrtT7ZHuV77 +qjvpdbNGEwz2fAAAAAAAAAAA//8AAAAAAAAJVmFsZW5jaWVzBQEACQAAAgAAAAAA +AAAA/wAAAAAAAAAJVm9pZFN0YXRlBQEAAAA= -----END STRICT TYPE LIB----- diff --git a/stl/RGB@0.1.0.stl b/stl/RGB@0.1.0.stl index 2e793558..3f56b3b4 100644 Binary files a/stl/RGB@0.1.0.stl and b/stl/RGB@0.1.0.stl differ diff --git a/stl/RGB@0.1.0.sty b/stl/RGB@0.1.0.sty index 4ba7db44..ba87d6c1 100644 --- a/stl/RGB@0.1.0.sty +++ b/stl/RGB@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: urn:ubideco:stl:DmN8aZj1dPvAvx5JYfz22azHs5RRbECxmxWoo5LK7E5f#house-herman-poem + Id: urn:ubideco:stl:AjePbbRf34u9Vx4iN8uyPZSaS5XC4jnTDpvMDePnerd1#medusa-boris-virtual Name: RGB Version: 0.1.0 Description: Consensus layer for RGB smart contracts @@ -211,8 +211,10 @@ data RevealedAttach :: id AttachId , salt U64 -- urn:ubideco:semid:3DcMJ3YRokNwKN8Cce1ZqsYpiTEuto7EY1szCMEDH97A#velvet-david-manual data RevealedData :: [Byte] --- urn:ubideco:semid:7j3XQz367V8aeQcMRK1aYTcbpjhHKCQcWNAJeUuYvVAC#record-domino-spirit -data RevealedFungible :: value FungibleState, blinding BlindingFactor +-- urn:ubideco:semid:GC8sb7Aw4uY6qVvFP3yy7th3onHPtxcqbuqn6pzpvWKN#pirate-evening-neon +data RevealedFungible :: value FungibleState + , blinding BlindingFactor + , assetTag [Byte ^ 32] -- urn:ubideco:semid:4SSnBqnEDnPxoBokzJpFx6XLrdWpRCBVhxmmVt6xsh8Z#gong-version-snow data Schema :: ffv Ffv , subsetOf ()?