Skip to content

Commit

Permalink
[gh-2295] add derive_multisig_xonly_pubkey_from_public_keys and deriv…
Browse files Browse the repository at this point in the history
…e_bitcoin_taproot_address_from_multisig_xonly_pubkey.
  • Loading branch information
Feliciss committed Jul 29, 2024
1 parent bd6dd6d commit 6a9a519
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 18 deletions.
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ fastcrypto-zkp = { version = "0.1.3" }
function_name = { version = "0.3.0" }
rustc-hash = { version = "2.0.0" }
xorf = { version = "0.11.0" }
musig2 = { version = "0.0.11" }

# Note: the BEGIN and END comments below are required for external tooling. Do not remove.
# BEGIN MOVE DEPENDENCIES
Expand Down
1 change: 1 addition & 0 deletions frameworks/rooch-framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ smallvec = { workspace = true }
hex = { workspace = true }
tracing = { workspace = true }
bitcoin = { workspace = true }
musig2 = { workspace = true }

move-binary-format = { workspace = true }
move-bytecode-utils = { workspace = true }
Expand Down
20 changes: 16 additions & 4 deletions frameworks/rooch-framework/doc/bitcoin_address.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
- [Function `verify_with_public_key`](#0x3_bitcoin_address_verify_with_public_key)
- [Function `to_rooch_address`](#0x3_bitcoin_address_to_rooch_address)
- [Function `verify_bitcoin_address_with_public_key`](#0x3_bitcoin_address_verify_bitcoin_address_with_public_key)
- [Function `derive_multi_sign_address`](#0x3_bitcoin_address_derive_multi_sign_address)
- [Function `derive_multisig_xonly_pubkey_from_public_keys`](#0x3_bitcoin_address_derive_multisig_xonly_pubkey_from_public_keys)
- [Function `derive_bitcoin_taproot_address_from_multisig_xonly_pubkey`](#0x3_bitcoin_address_derive_bitcoin_taproot_address_from_multisig_xonly_pubkey)


<pre><code><b>use</b> <a href="">0x1::string</a>;
Expand Down Expand Up @@ -287,11 +288,22 @@ Empty address is a special address that is used to if we parse address failed fr



<a name="0x3_bitcoin_address_derive_multi_sign_address"></a>
<a name="0x3_bitcoin_address_derive_multisig_xonly_pubkey_from_public_keys"></a>

## Function `derive_multi_sign_address`
## Function `derive_multisig_xonly_pubkey_from_public_keys`



<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_address.md#0x3_bitcoin_address_derive_multi_sign_address">derive_multi_sign_address</a>(public_keys: &<a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, threshold: u64): <a href="bitcoin_address.md#0x3_bitcoin_address_BitcoinAddress">bitcoin_address::BitcoinAddress</a>
<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_address.md#0x3_bitcoin_address_derive_multisig_xonly_pubkey_from_public_keys">derive_multisig_xonly_pubkey_from_public_keys</a>(public_keys: &<a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;, threshold: u64): <a href="">vector</a>&lt;u8&gt;
</code></pre>



<a name="0x3_bitcoin_address_derive_bitcoin_taproot_address_from_multisig_xonly_pubkey"></a>

## Function `derive_bitcoin_taproot_address_from_multisig_xonly_pubkey`



<pre><code><b>public</b> <b>fun</b> <a href="bitcoin_address.md#0x3_bitcoin_address_derive_bitcoin_taproot_address_from_multisig_xonly_pubkey">derive_bitcoin_taproot_address_from_multisig_xonly_pubkey</a>(xonly_pubkey: &<a href="">vector</a>&lt;u8&gt;): <a href="bitcoin_address.md#0x3_bitcoin_address_BitcoinAddress">bitcoin_address::BitcoinAddress</a>
</code></pre>
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ module rooch_framework::bitcoin_address {
// verify bitcoin address according to the pk bytes
public native fun verify_bitcoin_address_with_public_key(bitcoin_addr: &BitcoinAddress, pk: &vector<u8>): bool;

// derive multi signature address from public keys
public native fun derive_multi_sign_address(public_keys: &vector<vector<u8>>, threshold: u64): BitcoinAddress;
// derive multisig xonly public key from public keys
public native fun derive_multisig_xonly_pubkey_from_public_keys(public_keys: &vector<vector<u8>>, threshold: u64): vector<u8>;

// derive bitcoin taproot address from the multisig xonly public key
public native fun derive_bitcoin_taproot_address_from_multisig_xonly_pubkey(xonly_pubkey: &vector<u8>): BitcoinAddress;

/// Parse the Bitcoin address string bytes to Move BitcoinAddress
native fun parse(raw_addr: &vector<u8>): BitcoinAddress;
Expand Down Expand Up @@ -150,4 +153,37 @@ module rooch_framework::bitcoin_address {
let pk = x"038e3d29b653e40f5b620f9443ee05222d1e40be58f544b6fed3d464edd54db884";
assert!(!verify_with_public_key(&addr, &pk), 1004);
}

#[test]
fun test_derive_multisig_xonly_pubkey_from_public_keys_success() {
let expected_xonly_pubkey = x"ffa540e2d3df158dfb202fc1a2cbb20c4920ba35e8f75bb11101bfa47d71449a";
let pk_list = vector::empty<vector<u8>>();

let pk_1 = x"038e3d29b653e40f5b620f9443ee05222d1e40be58f544b6fed3d464edd54db883";
let pk_2 = x"02481521eb57656db4bc9ec81857e105cc7853fe8cad61be23667bb401840fc7f8";
let pk_3 = x"02c3bc6ff4dec7f43dd4f587d4dc227fb171755779425ca032e0fcb2f0bb639cc2";
let pk_4 = x"02ebdc1107552f81d188a2c63806cb6fa5d734eaa7316a85dc1f608fcaee412b72";

vector::push_back(&mut pk_list, pk_1);
vector::push_back(&mut pk_list, pk_2);
vector::push_back(&mut pk_list, pk_3);
vector::push_back(&mut pk_list, pk_4);

let xonly_pubkey = derive_multisig_xonly_pubkey_from_public_keys(&pk_list, 4);

assert!(expected_xonly_pubkey == xonly_pubkey, 1005);
}

#[test]
fun test_derive_bitcoin_taproot_address_from_multisig_xonly_pubkey_success() {
let xonly_pubkey = x"ffa540e2d3df158dfb202fc1a2cbb20c4920ba35e8f75bb11101bfa47d71449a";

let bitcoin_addr = derive_bitcoin_taproot_address_from_multisig_xonly_pubkey(&xonly_pubkey);

let expected_bitcoin_addr = BitcoinAddress {
bytes: b"bc1p8xpjpkc9uzj2dexcxjg9sw8lxje85xa4070zpcys589e3rf6k20qm6gjrt",
};

assert!(expected_bitcoin_addr.bytes == bitcoin_addr.bytes, 1006);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ crate::natives::gas_parameter::native::define_gas_parameters_for_natives!(GasPar
[.parse.per_byte, "parse.per_byte", 30 * MUL],
[.verify_bitcoin_address_with_public_key.base, "verify_bitcoin_address_with_public_key.base", 1000 * MUL],
[.verify_bitcoin_address_with_public_key.per_byte, "verify_bitcoin_address_with_public_key.per_byte", 30 * MUL],
[.derive_multi_sign_address.base, "parse.base", 1000 * MUL],
[.derive_multi_sign_address.per_byte, "parse.per_byte", 30 * MUL],
[.derive_multisig_xonly_pubkey_from_public_keys.base, "derive_multisig_xonly_pubkey_from_public_keys.base", 1000 * MUL],
[.derive_multisig_xonly_pubkey_from_public_keys.per_byte, "derive_multisig_xonly_pubkey_from_public_keys.per_byte", 30 * MUL],
[.derive_bitcoin_taproot_address_from_multisig_xonly_pubkey.base, "derive_bitcoin_taproot_address_from_multisig_xonly_pubkey.base", 1000 * MUL],
[.derive_bitcoin_taproot_address_from_multisig_xonly_pubkey.per_byte, "derive_bitcoin_taproot_address_from_multisig_xonly_pubkey.per_byte", 30 * MUL],
]);
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use move_vm_types::{
};
use moveos_stdlib::natives::helpers::{make_module_natives, make_native};
use moveos_types::state::{MoveState, MoveStructState};
use musig2::{secp::Point, secp256k1, KeyAggContext};
use rooch_types::address::BitcoinAddress;
use smallvec::smallvec;
use std::{collections::VecDeque, str::FromStr};
Expand Down Expand Up @@ -101,14 +102,73 @@ pub fn verify_bitcoin_address_with_public_key(
Ok(NativeResult::ok(cost, smallvec![Value::bool(is_ok)]))
}

// TODO: derive_multi_sign_address
pub fn derive_multi_sign_address(
_gas_params: &FromBytesGasParameters,
pub fn derive_multisig_xonly_pubkey_from_public_keys(
gas_params: &FromBytesGasParameters,
_context: &mut NativeContext,
_ty_args: Vec<Type>,
mut _args: VecDeque<Value>,
mut args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
todo!();
let threshold_bytes = pop_arg!(args, u64);
let pk_vec_bytes = pop_arg!(args, VectorRef);

let pk_vec_ref = pk_vec_bytes.as_bytes_ref();

let cost = gas_params.base
+ gas_params.per_byte * NumBytes::new(threshold_bytes + pk_vec_ref.len() as u64);

println!("{:?}", pk_vec_ref);

if pk_vec_ref.len() >= threshold_bytes as usize {
return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)]));
}

let pk = secp256k1::PublicKey::from_slice(&pk_vec_ref).expect("msg");

println!("{:?}", pk);

let pks = vec![pk];

println!("{:?}", pks);

let key_agg_ctx = KeyAggContext::new(pks).unwrap();

let aggregated_pubkey: Point = key_agg_ctx.aggregated_pubkey();

let xonly_pubkey = aggregated_pubkey.serialize_xonly();

Ok(NativeResult::ok(
cost,
smallvec![Value::vector_u8(xonly_pubkey)],
))
}

pub fn derive_bitcoin_taproot_address_from_multisig_xonly_pubkey(
gas_params: &FromBytesGasParameters,
_context: &mut NativeContext,
_ty_args: Vec<Type>,
mut args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
let xonly_pubkey_bytes = pop_arg!(args, VectorRef);

let xonly_pubkey_ref = xonly_pubkey_bytes.as_bytes_ref();

let cost = gas_params.base + gas_params.per_byte * NumBytes::new(xonly_pubkey_ref.len() as u64);

let internal_key = XOnlyPublicKey::from_slice(&xonly_pubkey_ref).unwrap();
let secp = bitcoin::secp256k1::Secp256k1::verification_only();
let bitcoin_addr = BitcoinAddress::from(bitcoin::Address::p2tr(
&secp,
internal_key,
None,
bitcoin::Network::Bitcoin,
));

println!("{:?}", bitcoin_addr);

Ok(NativeResult::ok(
cost,
smallvec![Value::struct_(bitcoin_addr.to_runtime_value_struct())],
))
}

#[derive(Debug, Clone)]
Expand All @@ -134,15 +194,18 @@ impl FromBytesGasParameters {
pub struct GasParameters {
pub parse: FromBytesGasParameters,
pub verify_bitcoin_address_with_public_key: FromBytesGasParameters,
pub derive_multi_sign_address: FromBytesGasParameters,
pub derive_multisig_xonly_pubkey_from_public_keys: FromBytesGasParameters,
pub derive_bitcoin_taproot_address_from_multisig_xonly_pubkey: FromBytesGasParameters,
}

impl GasParameters {
pub fn zeros() -> Self {
Self {
parse: FromBytesGasParameters::zeros(),
verify_bitcoin_address_with_public_key: FromBytesGasParameters::zeros(),
derive_multi_sign_address: FromBytesGasParameters::zeros(),
derive_multisig_xonly_pubkey_from_public_keys: FromBytesGasParameters::zeros(),
derive_bitcoin_taproot_address_from_multisig_xonly_pubkey:
FromBytesGasParameters::zeros(),
}
}
}
Expand All @@ -158,10 +221,17 @@ pub fn make_all(gas_params: GasParameters) -> impl Iterator<Item = (String, Nati
),
),
(
"derive_multi_sign_address",
"derive_multisig_xonly_pubkey_from_public_keys",
make_native(
gas_params.derive_multisig_xonly_pubkey_from_public_keys,
derive_multisig_xonly_pubkey_from_public_keys,
),
),
(
"derive_bitcoin_taproot_address_from_multisig_xonly_pubkey",
make_native(
gas_params.derive_multi_sign_address,
derive_multi_sign_address,
gas_params.derive_bitcoin_taproot_address_from_multisig_xonly_pubkey,
derive_bitcoin_taproot_address_from_multisig_xonly_pubkey,
),
),
];
Expand Down

0 comments on commit 6a9a519

Please sign in to comment.