diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index ac22c6b..02977ab 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -12,6 +12,17 @@ enum OpCode { PushData1 = 0x4c, PushData2 = 0x4d, PushData4 = 0x4e, + + // stack ops + Dup = 0x76, + + // bit logic + Equal = 0x87, + EqualVerify = 0x88, + + // crypto + Hash160 = 0xa9, + CheckSig = 0xac, } /// A serialized script, used inside transparent inputs and outputs of a transaction. @@ -59,9 +70,37 @@ impl Shl<&[u8]> for Script { } } +/// A transparent address corresponding to either a public key or a `Script`. +#[derive(Debug, PartialEq)] +pub enum TransparentAddress { + PublicKey([u8; 20]), + Script([u8; 20]), +} + +impl TransparentAddress { + /// Generate the `scriptPubKey` corresponding to this address. + pub fn script(&self) -> Script { + match self { + TransparentAddress::PublicKey(key_id) => { + // P2PKH script + Script::default() + << OpCode::Dup + << OpCode::Hash160 + << &key_id[..] + << OpCode::EqualVerify + << OpCode::CheckSig + } + TransparentAddress::Script(script_id) => { + // P2SH script + Script::default() << OpCode::Hash160 << &script_id[..] << OpCode::Equal + } + } + } +} + #[cfg(test)] mod tests { - use super::{OpCode, Script}; + use super::{OpCode, Script, TransparentAddress}; #[test] fn script_opcode() { @@ -102,4 +141,28 @@ mod tests { assert_eq!(&script.0[5..], &long_data[..]); } } + + #[test] + fn p2pkh() { + let addr = TransparentAddress::PublicKey([4; 20]); + assert_eq!( + &addr.script().0, + &[ + 0x76, 0xa9, 0x14, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x88, 0xac, + ] + ) + } + + #[test] + fn p2sh() { + let addr = TransparentAddress::Script([7; 20]); + assert_eq!( + &addr.script().0, + &[ + 0xa9, 0x14, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x87, + ] + ) + } }