btc_transaction_utils/
sign.rs

1// Copyright 2018 The Exonum Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Helper functions to create and verify segwit input signatures with the sighash all type.
16
17use bitcoin::{
18    blockdata::script::Script, blockdata::transaction::SigHashType,
19    util::bip143::SighashComponents, PublicKey,
20};
21use secp256k1::{self, Message, Secp256k1, SecretKey, Signature, Signing, Verification};
22
23use std::borrow::ToOwned;
24
25use crate::{Sha256dHash, TxInRef, UnspentTxOutValue};
26
27/// A signature data with the embedded sighash type byte.
28#[derive(Debug, Clone, PartialEq)]
29pub struct InputSignature(Vec<u8>);
30
31impl InputSignature {
32    /// Constructs input signature from the given signature data and the given sighash type.
33    pub fn new(mut inner: Vec<u8>, sighash_type: SigHashType) -> InputSignature {
34        inner.push(sighash_type as u8);
35        InputSignature(inner)
36    }
37
38    /// Tries to construct input signature from the raw bytes.
39    pub fn from_bytes(bytes: Vec<u8>) -> Result<InputSignature, secp256k1::Error> {
40        InputSignatureRef::from_bytes(bytes.as_ref())?;
41        Ok(InputSignature(bytes))
42    }
43
44    /// Returns the signature content in canonical form.
45    pub fn content(&self) -> &[u8] {
46        self.0.split_last().unwrap().1
47    }
48
49    /// Returns a sighash type of the given input signature.
50    pub fn sighash_type(&self) -> SigHashType {
51        let byte = *self.0.last().unwrap();
52        SigHashType::from_u32(u32::from(byte))
53    }
54}
55
56/// A borrowed equivalent of the `InputSignature` data type.
57/// It can be useful for checking incoming signatures from unauthorized sources.
58///
59/// # Examples
60///
61/// ```
62/// use secp256k1::Secp256k1;
63/// use btc_transaction_utils::InputSignatureRef;
64///
65/// // Get a signature from the unknown source.
66/// let bytes = hex::decode(
67///     "304402201538279618a4626653775069b43d4315c7d2ff3000\
68///      8d339d0ed31ff41e628e71022028f3182fc39df28201ca4d7d\
69///      489aece7bc5bc6bfe05b09b6a9d3b70bf5f3743101",
70/// ).unwrap();
71/// // Try to decode it.
72/// let signature = InputSignatureRef::from_bytes(&bytes)
73///     .expect("Signature should be correct");
74/// ```
75#[derive(Debug, Clone, Copy, PartialEq)]
76pub struct InputSignatureRef<'a>(&'a [u8]);
77
78impl<'a> InputSignatureRef<'a> {
79    /// Tries to construct input signature from the raw bytes.
80    pub fn from_bytes(bytes: &'a [u8]) -> Result<InputSignatureRef<'a>, secp256k1::Error> {
81        let (_sighash_type, content) = bytes
82            .split_last()
83            .ok_or_else(|| secp256k1::Error::InvalidMessage)?;
84        Signature::from_der(content)?;
85        Ok(InputSignatureRef(bytes))
86    }
87
88    /// Returns the signature content in canonical form.
89    pub fn content(&self) -> &[u8] {
90        self.0.split_last().unwrap().1
91    }
92
93    /// Returns a sighash type of the given input signature.
94    pub fn sighash_type(&self) -> SigHashType {
95        let byte = *self.0.last().unwrap();
96        SigHashType::from_u32(u32::from(byte))
97    }
98}
99
100impl From<InputSignature> for Vec<u8> {
101    fn from(s: InputSignature) -> Self {
102        s.0
103    }
104}
105
106impl AsRef<[u8]> for InputSignature {
107    fn as_ref(&self) -> &[u8] {
108        self.0.as_ref()
109    }
110}
111
112impl<'a> AsRef<[u8]> for InputSignatureRef<'a> {
113    fn as_ref(&self) -> &[u8] {
114        self.0
115    }
116}
117
118impl<'a> From<&'a InputSignature> for InputSignatureRef<'a> {
119    fn from(s: &'a InputSignature) -> InputSignatureRef {
120        InputSignatureRef(s.0.as_ref())
121    }
122}
123
124impl<'a> From<InputSignatureRef<'a>> for Vec<u8> {
125    fn from(s: InputSignatureRef<'a>) -> Vec<u8> {
126        s.0.to_owned()
127    }
128}
129
130impl<'a> From<InputSignatureRef<'a>> for InputSignature {
131    fn from(s: InputSignatureRef<'a>) -> InputSignature {
132        InputSignature(s.0.to_owned())
133    }
134}
135
136/// Computes the [`BIP-143`][bip-143] compliant sighash for a [`SIGHASH_ALL`][sighash_all]
137/// signature for the given input.
138///
139/// [bip-143]: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
140/// [sighash_all]: https://bitcoin.org/en/developer-guide#signature-hash-types
141pub fn signature_hash<'a, 'b, V: Into<UnspentTxOutValue<'b>>>(
142    txin: TxInRef<'a>,
143    script: &Script,
144    value: V,
145) -> Sha256dHash {
146    let value = value.into().balance(txin);
147    SighashComponents::new(txin.transaction)
148        .sighash_all(txin.as_ref(), script, value)
149        .as_hash()
150}
151
152/// Computes the [`BIP-143`][bip-143] compliant signature for the given input.
153/// [Read more...][signature-hash]
154///
155/// [bip-143]: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
156/// [signature-hash]: fn.signature_hash.html
157pub fn sign_input<'a, 'b, C, V>(
158    context: &mut Secp256k1<C>,
159    txin: TxInRef<'a>,
160    script: &Script,
161    value: V,
162    secret_key: &SecretKey,
163) -> Result<InputSignature, secp256k1::Error>
164where
165    C: Signing,
166    V: Into<UnspentTxOutValue<'b>>,
167{
168    // Computes sighash.
169    let sighash = signature_hash(txin, script, value);
170    // Makes signature.
171    let msg = Message::from_slice(&sighash[..])?;
172    let signature = context.sign(&msg, secret_key).serialize_der().to_vec();
173    Ok(InputSignature::new(signature, SigHashType::All))
174}
175
176/// Checks correctness of the signature for the given input.
177/// [Read more...][signature-hash]
178///
179/// [signature-hash]: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
180pub fn verify_input_signature<'a, 'b, C, V>(
181    context: &Secp256k1<C>,
182    txin: TxInRef<'a>,
183    script: &Script,
184    value: V,
185    public_key: &PublicKey,
186    signature: &[u8],
187) -> Result<(), secp256k1::Error>
188where
189    C: Verification,
190    V: Into<UnspentTxOutValue<'b>>,
191{
192    // Computes sighash.
193    let sighash = signature_hash(txin, script, value);
194    // Verifies signature.
195    let msg = Message::from_slice(&sighash[..])?;
196    let sign = Signature::from_der(signature)?;
197    context.verify(&msg, &sign, &public_key.key)
198}
199
200#[test]
201fn test_input_signature_ref_incorrect() {
202    let bytes = b"abacaba";
203    InputSignatureRef::from_bytes(bytes).expect_err("Signature should be incorrect");
204    InputSignature::from_bytes(bytes.to_vec()).expect_err("Signature should be incorrect");
205}
206
207#[test]
208fn test_input_signature_ref_correct() {
209    let bytes = ::hex::decode(
210        "304402201538279618a4626653775069b43d4315c7d2ff30008d339d0ed31ff41e628e71022028f3182fc39df\
211         28201ca4d7d489aece7bc5bc6bfe05b09b6a9d3b70bf5f3743101",
212    )
213    .unwrap();
214    InputSignatureRef::from_bytes(&bytes).expect("Signature should be correct");
215    InputSignature::from_bytes(bytes).expect("Signature should be correct");
216}