segwit.rs (6009B)
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 std::cmp::Ordering; 17 18 use bech32::Hrp; 19 use depolymerizer_common::rand_slice; 20 use rand::rngs::ThreadRng; 21 use taler_common::api::{EddsaPublicKey, EddsaPublicKeyError}; 22 23 // TODO use segwit v1 to only use a single address 24 25 /// Encode metadata into a segwit address 26 pub fn encode_segwit_addr(hrp: Hrp, metada: &[u8; 20]) -> String { 27 bech32::segwit::encode_v0(hrp, metada).unwrap() 28 } 29 30 /// Encode half of a 32B key into a segwit address 31 fn encode_segwit_key_half( 32 hrp: Hrp, 33 is_first: bool, 34 prefix: &[u8; 4], 35 key_half: &[u8; 16], 36 ) -> String { 37 // Combine prefix and the key half 38 let mut buf = [0u8; 20]; 39 buf[..4].copy_from_slice(prefix); 40 buf[4..].copy_from_slice(key_half); 41 // Toggle first bit for ordering 42 if is_first { 43 buf[0] &= 0b0111_1111 // Unset first bit 44 } else { 45 buf[0] |= 0b1000_0000 // Set first bit 46 } 47 // Encode into an fake segwit address 48 encode_segwit_addr(hrp, &buf) 49 } 50 51 /// Encode a 32B key into two segwit addresses 52 pub fn encode_segwit_key(hrp: Hrp, msg: &[u8; 32]) -> [String; 2] { 53 // Generate a random prefix 54 let prefix = rand_slice(); 55 // Split key in half; 56 let split: (&[u8; 16], &[u8; 16]) = 57 (msg[..16].try_into().unwrap(), msg[16..].try_into().unwrap()); 58 [ 59 encode_segwit_key_half(hrp, true, &prefix, split.0), 60 encode_segwit_key_half(hrp, false, &prefix, split.1), 61 ] 62 } 63 64 #[derive(Debug, thiserror::Error)] 65 pub enum DecodeSegWitErr { 66 #[error("There is less than 2 segwit addresses")] 67 MissingSegWitAddress, 68 #[error("No addresses are sharing a common prefix")] 69 NoPrefixMatch, 70 #[error("More than two addresses are sharing a common prefix")] 71 PrefixCollision, 72 #[error(transparent)] 73 Malformed(EddsaPublicKeyError), 74 } 75 76 /// Decode a 32B key into from addresses 77 pub fn decode_segwit_msg( 78 segwit_addrs: &[impl AsRef<str>], 79 ) -> Result<EddsaPublicKey, DecodeSegWitErr> { 80 // Extract parts from every addresses 81 let decoded: Vec<(bool, [u8; 4], [u8; 16])> = segwit_addrs 82 .iter() 83 .filter_map(|addr| { 84 bech32::segwit::decode(addr.as_ref()) 85 .ok() 86 .and_then(|(_, _, pg)| { 87 if pg.len() == 20 { 88 let mut prefix: [u8; 4] = pg[..4].try_into().unwrap(); 89 let key_half: [u8; 16] = pg[4..].try_into().unwrap(); 90 let is_first = !pg[0] & 0b1000_0000 == 0; 91 // Clear first bit 92 prefix[0] &= 0b0111_1111; 93 Some((is_first, prefix, key_half)) 94 } else { 95 None 96 } 97 }) 98 }) 99 .collect(); 100 101 if decoded.len() < 2 { 102 return Err(DecodeSegWitErr::MissingSegWitAddress); 103 } 104 // Keep only the addresses with duplicated prefix 105 // TODO use sort_unstable_by and partition_dedup_by_key when stable 106 let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded 107 .iter() 108 .filter(|(_, prefix, _)| { 109 decoded 110 .iter() 111 .filter(|(_, other, _)| other == prefix) 112 .count() 113 > 1 114 }) 115 .collect(); 116 117 match matches.len().cmp(&2) { 118 Ordering::Equal => { 119 let mut key = [0; 32]; 120 for (is_first, _, half) in matches { 121 key[*is_first as usize * 16..][..16].copy_from_slice(half); 122 } 123 EddsaPublicKey::try_from(key).map_err(DecodeSegWitErr::Malformed) 124 } 125 Ordering::Greater => Err(DecodeSegWitErr::PrefixCollision), 126 Ordering::Less => Err(DecodeSegWitErr::MissingSegWitAddress), 127 } 128 } 129 130 // TODO find a way to hide that function while using it in test and benchmark 131 pub fn rand_addresses(hrp: Hrp, key: &[u8; 32]) -> Vec<String> { 132 use rand::prelude::SliceRandom; 133 134 let mut rng_address: Vec<String> = 135 std::iter::repeat_with(|| encode_segwit_addr(hrp, &rand_slice())) 136 .take(2) 137 .collect(); 138 139 let mut addresses = encode_segwit_key(hrp, key).to_vec(); 140 addresses.append(&mut rng_address); 141 addresses.shuffle(&mut ThreadRng::default()); 142 addresses 143 } 144 145 #[cfg(test)] 146 mod test { 147 use rand::{prelude::SliceRandom, rngs::ThreadRng}; 148 use taler_common::api::EddsaPublicKey; 149 150 use crate::segwit::{decode_segwit_msg, encode_segwit_key, rand_addresses}; 151 152 #[test] 153 fn test_shuffle() { 154 let mut rng = ThreadRng::default(); 155 for _ in 0..1000 { 156 let key = EddsaPublicKey::rand(); 157 let mut addresses = encode_segwit_key(bech32::hrp::TB, &key); 158 addresses.shuffle(&mut rng); 159 let decoded = 160 decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) 161 .unwrap(); 162 assert_eq!(key, decoded); 163 } 164 } 165 166 #[test] 167 fn test_shuffle_many() { 168 for _ in 0..1000 { 169 let key = EddsaPublicKey::rand(); 170 let addresses = rand_addresses(bech32::hrp::TB, &key); 171 let decoded = 172 decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) 173 .unwrap(); 174 assert_eq!(key, decoded); 175 } 176 } 177 }