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 }