depolymerization

wire gateway for Bitcoin/Ethereum
Log | Files | Refs | Submodules | README | LICENSE

segwit.rs (5887B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2022-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 use bech32::Hrp;
     17 use depolymerizer_common::rand_slice;
     18 use rand::rngs::ThreadRng;
     19 use std::cmp::Ordering;
     20 use taler_common::api_common::EddsaPublicKey;
     21 
     22 // TODO use segwit v1 to only use a single address
     23 
     24 /// Encode metadata into a segwit address
     25 pub fn encode_segwit_addr(hrp: Hrp, metada: &[u8; 20]) -> String {
     26     bech32::segwit::encode_v0(hrp, metada).unwrap()
     27 }
     28 
     29 /// Encode half of a 32B key into a segwit address
     30 fn encode_segwit_key_half(
     31     hrp: Hrp,
     32     is_first: bool,
     33     prefix: &[u8; 4],
     34     key_half: &[u8; 16],
     35 ) -> String {
     36     // Combine prefix and the key half
     37     let mut buf = [0u8; 20];
     38     buf[..4].copy_from_slice(prefix);
     39     buf[4..].copy_from_slice(key_half);
     40     // Toggle first bit for ordering
     41     if is_first {
     42         buf[0] &= 0b0111_1111 // Unset first bit
     43     } else {
     44         buf[0] |= 0b1000_0000 // Set first bit
     45     }
     46     // Encode into an fake segwit address
     47     encode_segwit_addr(hrp, &buf)
     48 }
     49 
     50 /// Encode a 32B key into two segwit addresses
     51 pub fn encode_segwit_key(hrp: Hrp, msg: &[u8; 32]) -> [String; 2] {
     52     // Generate a random prefix
     53     let prefix = rand_slice();
     54     // Split key in half;
     55     let split: (&[u8; 16], &[u8; 16]) =
     56         (msg[..16].try_into().unwrap(), msg[16..].try_into().unwrap());
     57     [
     58         encode_segwit_key_half(hrp, true, &prefix, split.0),
     59         encode_segwit_key_half(hrp, false, &prefix, split.1),
     60     ]
     61 }
     62 
     63 #[derive(Debug, Clone, thiserror::Error)]
     64 pub enum DecodeSegWitErr {
     65     #[error("There is less than 2 segwit addresses")]
     66     MissingSegWitAddress,
     67     #[error("No addresses are sharing a common prefix")]
     68     NoPrefixMatch,
     69     #[error("More than two addresses are sharing a common prefix")]
     70     PrefixCollision,
     71 }
     72 
     73 /// Decode a 32B key into from addresses
     74 pub fn decode_segwit_msg(
     75     segwit_addrs: &[impl AsRef<str>],
     76 ) -> Result<EddsaPublicKey, DecodeSegWitErr> {
     77     // Extract parts from every addresses
     78     let decoded: Vec<(bool, [u8; 4], [u8; 16])> = segwit_addrs
     79         .iter()
     80         .filter_map(|addr| {
     81             bech32::segwit::decode(addr.as_ref())
     82                 .ok()
     83                 .and_then(|(_, _, pg)| {
     84                     if pg.len() == 20 {
     85                         let mut prefix: [u8; 4] = pg[..4].try_into().unwrap();
     86                         let key_half: [u8; 16] = pg[4..].try_into().unwrap();
     87                         let is_first = !pg[0] & 0b1000_0000 == 0;
     88                         // Clear first bit
     89                         prefix[0] &= 0b0111_1111;
     90                         Some((is_first, prefix, key_half))
     91                     } else {
     92                         None
     93                     }
     94                 })
     95         })
     96         .collect();
     97 
     98     if decoded.len() < 2 {
     99         return Err(DecodeSegWitErr::MissingSegWitAddress);
    100     }
    101     // Keep only the addresses with duplicated prefix
    102     // TODO use sort_unstable_by and partition_dedup_by_key when stable
    103     let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded
    104         .iter()
    105         .filter(|(_, prefix, _)| {
    106             decoded
    107                 .iter()
    108                 .filter(|(_, other, _)| other == prefix)
    109                 .count()
    110                 > 1
    111         })
    112         .collect();
    113 
    114     match matches.len().cmp(&2) {
    115         Ordering::Equal => {
    116             let mut key = [0; 32];
    117             for (is_first, _, half) in matches {
    118                 key[*is_first as usize * 16..][..16].copy_from_slice(half);
    119             }
    120             Ok(EddsaPublicKey::from(key))
    121         }
    122         Ordering::Greater => Err(DecodeSegWitErr::PrefixCollision),
    123         Ordering::Less => Err(DecodeSegWitErr::MissingSegWitAddress),
    124     }
    125 }
    126 
    127 // TODO find a way to hide that function while using it in test and benchmark
    128 pub fn rand_addresses(hrp: Hrp, key: &[u8; 32]) -> Vec<String> {
    129     use rand::prelude::SliceRandom;
    130 
    131     let mut rng_address: Vec<String> =
    132         std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_slice()))
    133             .take(2)
    134             .collect();
    135 
    136     let mut addresses = encode_segwit_key(hrp, key).to_vec();
    137     addresses.append(&mut rng_address);
    138     addresses.shuffle(&mut ThreadRng::default());
    139     addresses
    140 }
    141 
    142 #[cfg(test)]
    143 mod test {
    144     use rand::{prelude::SliceRandom, rngs::ThreadRng};
    145     use taler_common::types::base32::Base32;
    146 
    147     use crate::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses};
    148 
    149     #[test]
    150     fn test_shuffle() {
    151         let mut rng = ThreadRng::default();
    152         for _ in 0..1000 {
    153             let key = Base32::rand();
    154             let mut addresses = encode_segwit_key(bech32::hrp::TB, &key);
    155             addresses.shuffle(&mut rng);
    156             let decoded =
    157                 decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
    158                     .unwrap();
    159             assert_eq!(key, decoded);
    160         }
    161     }
    162 
    163     #[test]
    164     fn test_shuffle_many() {
    165         for _ in 0..1000 {
    166             let key = Base32::rand();
    167             let addresses = rand_addresses(bech32::hrp::TB, &key);
    168             let decoded =
    169                 decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
    170                     .unwrap();
    171             assert_eq!(key, decoded);
    172         }
    173     }
    174 }