taproot_assets_zk_core/
lib.rs1#![no_std]
2#![no_main]
3
4extern crate alloc;
5
6pub mod verify;
8
9use bitcoin::TapNodeHash;
10use bitcoin::hashes::Hash;
11use bitcoin::key::TapTweak;
12use bitcoin::secp256k1::{PublicKey as SecpPublicKey, Scalar, Secp256k1};
13use taproot_assets_core::{OpsError, TaprootOps};
14use taproot_assets_types::asset::SerializedKey;
15
16#[derive(Debug, Clone, Copy, Default)]
18pub struct Risc0TaprootOps;
19
20impl TaprootOps for Risc0TaprootOps {
21 type PubKey = SecpPublicKey;
22
23 fn parse_group_key(&self, key: &SerializedKey) -> Result<Self::PubKey, OpsError> {
24 SecpPublicKey::from_slice(&key.bytes).map_err(|_| OpsError::InvalidRawGroupKey)
25 }
26
27 fn parse_internal_key(&self, key: &SerializedKey) -> Result<Self::PubKey, OpsError> {
28 SecpPublicKey::from_slice(&key.bytes).map_err(|_| OpsError::InvalidInternalKey)
29 }
30
31 fn add_tweak(&self, pubkey: &Self::PubKey, tweak: [u8; 32]) -> Result<Self::PubKey, OpsError> {
32 let secp = Secp256k1::verification_only();
33 let scalar = Scalar::from_be_bytes(tweak).map_err(|_| OpsError::AssetIdTweakOutOfRange)?;
34 pubkey
35 .add_exp_tweak(&secp, &scalar)
36 .map_err(|_| OpsError::InvalidGroupKeyTweak)
37 }
38
39 fn taproot_output_key(
40 &self,
41 internal_key: &Self::PubKey,
42 tapscript_root: Option<[u8; 32]>,
43 ) -> Result<SerializedKey, OpsError> {
44 let secp = Secp256k1::verification_only();
45 let merkle_root = tapscript_root.map(TapNodeHash::from_byte_array);
46 let (xonly_key, _) = internal_key.x_only_public_key();
47 let (tweaked, parity) = xonly_key.tap_tweak(&secp, merkle_root);
48 let output_key =
49 SecpPublicKey::from_x_only_public_key(tweaked.to_x_only_public_key(), parity);
50
51 Ok(SerializedKey {
52 bytes: output_key.serialize(),
53 })
54 }
55}