Skip to content

Commit

Permalink
dbc: refactor validation workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Dec 14, 2023
1 parent 38e0447 commit fbdd7f3
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 71 deletions.
2 changes: 1 addition & 1 deletion consensus/src/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl ScriptPubkey {
}

#[inline]
pub fn is_op_return(&self) -> bool { self[0] == OpCode::Return as u8 }
pub fn is_op_return(&self) -> bool { !self.is_empty() && self[0] == OpCode::Return as u8 }

Check warning on line 151 in consensus/src/script.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/script.rs#L151

Added line #L151 was not covered by tests

/// Adds a single opcode to the script.
#[inline]
Expand Down
18 changes: 10 additions & 8 deletions dbc/src/anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,16 @@ impl<D: dbc::Proof> PartialOrd for Anchor<mpc::MerkleBlock, D> {
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum MergeError {
/// Error merging two LNPBP-4 proofs, which are unrelated.
/// Error merging two MPC proofs, which are unrelated.
#[display(inner)]
#[from]
Lnpbp4Mismatch(mpc::MergeError),
MpcMismatch(mpc::MergeError),

/// anchors can't be merged since they have different witness transactions
TxidMismatch,

/// anchors can't be merged since they have different proofs
ProofMismatch,
/// anchors can't be merged since they have different DBC proofs
DbcMismatch,
}

impl<D: dbc::Proof> Anchor<mpc::MerkleBlock, D> {
Expand Down Expand Up @@ -178,10 +178,12 @@ impl<D: dbc::Proof> Anchor<mpc::MerkleProof, D> {
protocol_id: impl Into<ProtocolId>,
message: Message,
tx: &Tx,
) -> Result<(), VerifyError<D::Error>> {
) -> Result<mpc::Commitment, VerifyError<D::Error>> {
let mpc_commitment = self.convolve(protocol_id, message)?;

Check warning on line 182 in dbc/src/anchor.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/anchor.rs#L181-L182

Added lines #L181 - L182 were not covered by tests
self.dbc_proof
.verify(&self.mpc_proof.convolve(protocol_id.into(), message)?, tx)
.map_err(VerifyError::Dbc)
.verify(&mpc_commitment, tx)
.map_err(VerifyError::Dbc)?;
Ok(mpc_commitment)

Check warning on line 186 in dbc/src/anchor.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/anchor.rs#L184-L186

Added lines #L184 - L186 were not covered by tests
}

/// Verifies that the anchor commits to the given message under the given
Expand Down Expand Up @@ -233,7 +235,7 @@ impl<D: dbc::Proof> Anchor<mpc::MerkleBlock, D> {
return Err(MergeError::TxidMismatch);
}
if self.dbc_proof != other.dbc_proof {
return Err(MergeError::ProofMismatch);
return Err(MergeError::DbcMismatch);

Check warning on line 238 in dbc/src/anchor.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/anchor.rs#L238

Added line #L238 was not covered by tests
}
self.mpc_proof.merge_reveal(other.mpc_proof)?;
Ok(self)
Expand Down
56 changes: 22 additions & 34 deletions dbc/src/opret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,37 @@

//! ScriptPubkey-based OP_RETURN commitments.
use bc::{ScriptPubkey, Tx, Txid};
mod tx;
mod txout;
mod spk;

use bc::Tx;
use commit_verify::mpc::Commitment;
use commit_verify::{CommitmentProtocol, EmbedCommitVerify, EmbedVerifyError};

use crate::{Proof, LIB_NAME_BPCORE};

/// Errors covering failed anchor validation.
/// Marker non-instantiable enum defining LNPBP-12 taproot OP_RETURN (`tapret`)
/// protocol.
pub enum Opret {}

impl CommitmentProtocol for Opret {}

/// Errors during tapret commitment.
#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]

Check warning on line 41 in dbc/src/opret/mod.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/mod.rs#L41

Added line #L41 was not covered by tests
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),

Check warning on line 44 in dbc/src/opret/mod.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/mod.rs#L44

Added line #L44 was not covered by tests
serde(crate = "serde_crate", rename_all = "camelCase")
)]
#[display(doc_comments)]
pub enum OpretVerifyError {
/// witness transaction {txid} contains invalid OP_RETURN commitment
/// {present:x} instead of {expected:x}.
OpretMismatch {
/// Transaction id
txid: Txid,
/// Commitment from the first OP_RETURN transaction output
present: ScriptPubkey,
/// Expected commitment absent in the first OP_RETURN transaction output
expected: ScriptPubkey,
},
pub enum OpretError {
/// transaction doesn't contain OP_RETURN output.
NoOpretOutput,

/// witness transaction {0} does not contain any OP_RETURN commitment
/// required by the seal definition.
OpretAbsent(Txid),
/// first OP_RETURN output inside the transaction already contains some
/// data.
InvalidOpretScript,
}

/// Empty type for use inside [`crate::Anchor`] for opret commitment scheme.
Expand All @@ -65,24 +68,9 @@ pub enum OpretVerifyError {
pub struct OpretProof(());

impl Proof for OpretProof {
type Error = OpretVerifyError;
type Error = EmbedVerifyError<OpretError>;

fn verify(&self, msg: &Commitment, tx: &Tx) -> Result<(), OpretVerifyError> {
// TODO: Use embed-commit-verify
for txout in &tx.outputs {
if txout.script_pubkey.is_op_return() {
let expected = ScriptPubkey::op_return(msg.as_slice());
if txout.script_pubkey == expected {
return Ok(());
} else {
return Err(OpretVerifyError::OpretMismatch {
txid: tx.txid(),
present: txout.script_pubkey.clone(),
expected,
});
}
}
}
Err(OpretVerifyError::OpretAbsent(tx.txid()))
fn verify(&self, msg: &Commitment, tx: &Tx) -> Result<(), EmbedVerifyError<OpretError>> {
tx.verify(msg, self)
}

Check warning on line 75 in dbc/src/opret/mod.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/mod.rs#L73-L75

Added lines #L73 - L75 were not covered by tests
}
58 changes: 58 additions & 0 deletions dbc/src/opret/spk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Deterministic bitcoin commitments library.
//
// SPDX-License-Identifier: Apache-2.0
//
// Written in 2019-2023 by
// Dr Maxim Orlovsky <[email protected]>
//
// Copyright (C) 2019-2023 LNP/BP Standards Association. 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 bc::opcodes::OP_RETURN;
use bc::ScriptPubkey;
use commit_verify::mpc::Commitment;
use commit_verify::{EmbedCommitProof, EmbedCommitVerify, EmbedVerifyError};

use crate::opret::{Opret, OpretError, OpretProof};

impl EmbedCommitProof<Commitment, ScriptPubkey, Opret> for OpretProof {
fn restore_original_container(
&self,
commit_container: &ScriptPubkey,
) -> Result<ScriptPubkey, EmbedVerifyError<OpretError>> {
if !commit_container.is_op_return() {
return Err(OpretError::NoOpretOutput.into());
}
if commit_container.len() != 34 {
return Err(OpretError::InvalidOpretScript.into());
}
Ok(ScriptPubkey::from_unsafe(vec![OP_RETURN]))
}

Check warning on line 41 in dbc/src/opret/spk.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/spk.rs#L30-L41

Added lines #L30 - L41 were not covered by tests
}

impl EmbedCommitVerify<Commitment, Opret> for ScriptPubkey {
type Proof = OpretProof;
type CommitError = OpretError;

fn embed_commit(&mut self, msg: &Commitment) -> Result<Self::Proof, Self::CommitError> {
if !self.is_op_return() {
return Err(OpretError::NoOpretOutput);
}
if self.len() != 1 {
return Err(OpretError::InvalidOpretScript);
}
*self = ScriptPubkey::op_return(msg.as_slice());
Ok(OpretProof::default())
}

Check warning on line 57 in dbc/src/opret/spk.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/spk.rs#L48-L57

Added lines #L48 - L57 were not covered by tests
}
56 changes: 56 additions & 0 deletions dbc/src/opret/tx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Deterministic bitcoin commitments library.
//
// SPDX-License-Identifier: Apache-2.0
//
// Written in 2019-2023 by
// Dr Maxim Orlovsky <[email protected]>
//
// Copyright (C) 2019-2023 LNP/BP Standards Association. 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 bc::Tx;
use commit_verify::mpc::Commitment;
use commit_verify::{EmbedCommitProof, EmbedCommitVerify, EmbedVerifyError};

use super::{Opret, OpretError, OpretProof};

impl EmbedCommitProof<Commitment, Tx, Opret> for OpretProof {
fn restore_original_container(
&self,
commit_container: &Tx,
) -> Result<Tx, EmbedVerifyError<OpretError>> {
let mut tx = commit_container.clone();
for txout in &mut tx.outputs {
if txout.script_pubkey.is_op_return() {
*txout = self.restore_original_container(txout)?;
return Ok(tx);
}

Check warning on line 38 in dbc/src/opret/tx.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/tx.rs#L29-L38

Added lines #L29 - L38 were not covered by tests
}
Err(OpretError::NoOpretOutput.into())
}

Check warning on line 41 in dbc/src/opret/tx.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/tx.rs#L40-L41

Added lines #L40 - L41 were not covered by tests
}

impl EmbedCommitVerify<Commitment, Opret> for Tx {
type Proof = OpretProof;
type CommitError = OpretError;

fn embed_commit(&mut self, msg: &Commitment) -> Result<Self::Proof, Self::CommitError> {
for txout in &mut self.outputs {
if txout.script_pubkey.is_op_return() {
return txout.script_pubkey.embed_commit(msg);
}

Check warning on line 52 in dbc/src/opret/tx.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/tx.rs#L48-L52

Added lines #L48 - L52 were not covered by tests
}
Err(OpretError::NoOpretOutput)
}

Check warning on line 55 in dbc/src/opret/tx.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/tx.rs#L54-L55

Added lines #L54 - L55 were not covered by tests
}
46 changes: 46 additions & 0 deletions dbc/src/opret/txout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Deterministic bitcoin commitments library.
//
// SPDX-License-Identifier: Apache-2.0
//
// Written in 2019-2023 by
// Dr Maxim Orlovsky <[email protected]>
//
// Copyright (C) 2019-2023 LNP/BP Standards Association. 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 bc::TxOut;
use commit_verify::mpc::Commitment;
use commit_verify::{EmbedCommitProof, EmbedCommitVerify, EmbedVerifyError};

use crate::opret::{Opret, OpretError, OpretProof};

impl EmbedCommitProof<Commitment, TxOut, Opret> for OpretProof {
fn restore_original_container(
&self,
commit_container: &TxOut,
) -> Result<TxOut, EmbedVerifyError<OpretError>> {
let mut txout = commit_container.clone();
txout.script_pubkey = self.restore_original_container(&txout.script_pubkey)?;
Ok(txout)
}

Check warning on line 36 in dbc/src/opret/txout.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/txout.rs#L29-L36

Added lines #L29 - L36 were not covered by tests
}

impl EmbedCommitVerify<Commitment, Opret> for TxOut {
type Proof = OpretProof;
type CommitError = OpretError;

fn embed_commit(&mut self, msg: &Commitment) -> Result<Self::Proof, Self::CommitError> {
self.script_pubkey.embed_commit(msg)
}

Check warning on line 45 in dbc/src/opret/txout.rs

View check run for this annotation

Codecov / codecov/patch

dbc/src/opret/txout.rs#L43-L45

Added lines #L43 - L45 were not covered by tests
}
17 changes: 8 additions & 9 deletions dbc/src/tapret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,21 @@ mod txout;
mod spk;
mod xonlypk;

pub use tapscript::{TapretCommitment, TAPRET_SCRIPT_COMMITMENT_PREFIX};
pub use tx::TapretError;
pub use xonlypk::TapretKeyError;

/// Marker non-instantiable enum defining LNPBP-12 taproot OP_RETURN (`tapret`)
/// protocol.
pub enum Lnpbp12 {}

use bc::{InternalPk, IntoTapHash, LeafScript, ScriptPubkey, TapBranchHash, TapNodeHash, Tx};
use commit_verify::mpc::Commitment;
use commit_verify::{CommitmentProtocol, ConvolveCommitProof, ConvolveVerifyError};
use strict_encoding::{StrictDeserialize, StrictSerialize};
pub use tapscript::{TapretCommitment, TAPRET_SCRIPT_COMMITMENT_PREFIX};
pub use tx::TapretError;
pub use xonlypk::TapretKeyError;

use crate::{Proof, LIB_NAME_BPCORE};

impl CommitmentProtocol for Lnpbp12 {}
/// Marker non-instantiable enum defining LNPBP-12 taproot OP_RETURN (`tapret`)
/// protocol.
pub enum Tapret {}

impl CommitmentProtocol for Tapret {}

/// Errors in constructing tapret path proof [`TapretPathProof`].
#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)]
Expand Down
6 changes: 3 additions & 3 deletions dbc/src/tapret/spk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@
use bc::ScriptPubkey;
use commit_verify::{mpc, ConvolveCommit, ConvolveCommitProof};

use super::{Lnpbp12, TapretKeyError, TapretProof};
use super::{Tapret, TapretKeyError, TapretProof};

impl ConvolveCommitProof<mpc::Commitment, ScriptPubkey, Lnpbp12> for TapretProof {
impl ConvolveCommitProof<mpc::Commitment, ScriptPubkey, Tapret> for TapretProof {
type Suppl = Self;

fn restore_original(&self, _: &ScriptPubkey) -> ScriptPubkey { self.original_pubkey_script() }

fn extract_supplement(&self) -> &Self::Suppl { self }
}

impl ConvolveCommit<mpc::Commitment, TapretProof, Lnpbp12> for ScriptPubkey {
impl ConvolveCommit<mpc::Commitment, TapretProof, Tapret> for ScriptPubkey {
type Commitment = ScriptPubkey;
type CommitError = TapretKeyError;

Expand Down
4 changes: 2 additions & 2 deletions dbc/src/tapret/tapscript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use bc::{TapCode, TapScript};
use commit_verify::{mpc, CommitEncode, CommitVerify};
use strict_encoding::{DecodeError, DeserializeError, StrictDeserialize, StrictSerialize};

use super::Lnpbp12;
use super::Tapret;
use crate::LIB_NAME_BPCORE;

/// Hardcoded tapret script prefix consisting of 29 `OP_RESERVED` pushes,
Expand Down Expand Up @@ -99,7 +99,7 @@ impl TapretCommitment {
pub fn with(mpc: mpc::Commitment, nonce: u8) -> Self { Self { mpc, nonce } }
}

impl CommitVerify<TapretCommitment, Lnpbp12> for TapScript {
impl CommitVerify<TapretCommitment, Tapret> for TapScript {
/// Tapret script consists of 29 `OP_RESERVED` pushes, followed by
/// `OP_RETURN`, `OP_PUSHBYTES_33` and serialized commitment data (MPC
/// commitment + nonce as a single slice).
Expand Down
6 changes: 3 additions & 3 deletions dbc/src/tapret/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use bc::Tx;
use commit_verify::{mpc, ConvolveCommit, ConvolveCommitProof};

use super::{Lnpbp12, TapretKeyError, TapretProof};
use super::{Tapret, TapretKeyError, TapretProof};

/// Errors during tapret commitment.
#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
Expand All @@ -42,7 +42,7 @@ pub enum TapretError {
NoTaprootOutput,
}

impl ConvolveCommitProof<mpc::Commitment, Tx, Lnpbp12> for TapretProof {
impl ConvolveCommitProof<mpc::Commitment, Tx, Tapret> for TapretProof {
type Suppl = Self;

fn restore_original(&self, commitment: &Tx) -> Tx {
Expand All @@ -59,7 +59,7 @@ impl ConvolveCommitProof<mpc::Commitment, Tx, Lnpbp12> for TapretProof {
fn extract_supplement(&self) -> &Self::Suppl { self }
}

impl ConvolveCommit<mpc::Commitment, TapretProof, Lnpbp12> for Tx {
impl ConvolveCommit<mpc::Commitment, TapretProof, Tapret> for Tx {
type Commitment = Tx;
type CommitError = TapretError;

Expand Down
Loading

0 comments on commit fbdd7f3

Please sign in to comment.