{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
module Haskoin.Address.Bech32 (
HRP,
Bech32,
Bech32Encoding (..),
bech32Const,
Data,
bech32Encode,
bech32Decode,
toBase32,
toBase256,
segwitEncode,
segwitDecode,
Word5 (..),
word5,
fromWord5,
) where
import Control.Monad (guard)
import Data.Array (
Array,
assocs,
bounds,
listArray,
(!),
(//),
)
import Data.Bits (
Bits,
testBit,
unsafeShiftL,
unsafeShiftR,
xor,
(.&.),
(.|.),
)
import qualified Data.ByteString as B
import Data.Char (toUpper)
import Data.Foldable (foldl')
import Data.Functor.Identity (Identity, runIdentity)
import Data.Ix (Ix (..))
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Word (Word8)
data Bech32Encoding = Bech32 | Bech32m
deriving (Bech32Encoding -> Bech32Encoding -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Bech32Encoding -> Bech32Encoding -> Bool
$c/= :: Bech32Encoding -> Bech32Encoding -> Bool
== :: Bech32Encoding -> Bech32Encoding -> Bool
$c== :: Bech32Encoding -> Bech32Encoding -> Bool
Eq, Int -> Bech32Encoding -> ShowS
[Bech32Encoding] -> ShowS
Bech32Encoding -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [Bech32Encoding] -> ShowS
$cshowList :: [Bech32Encoding] -> ShowS
show :: Bech32Encoding -> [Char]
$cshow :: Bech32Encoding -> [Char]
showsPrec :: Int -> Bech32Encoding -> ShowS
$cshowsPrec :: Int -> Bech32Encoding -> ShowS
Show, Eq Bech32Encoding
Bech32Encoding -> Bech32Encoding -> Bool
Bech32Encoding -> Bech32Encoding -> Ordering
Bech32Encoding -> Bech32Encoding -> Bech32Encoding
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Bech32Encoding -> Bech32Encoding -> Bech32Encoding
$cmin :: Bech32Encoding -> Bech32Encoding -> Bech32Encoding
max :: Bech32Encoding -> Bech32Encoding -> Bech32Encoding
$cmax :: Bech32Encoding -> Bech32Encoding -> Bech32Encoding
>= :: Bech32Encoding -> Bech32Encoding -> Bool
$c>= :: Bech32Encoding -> Bech32Encoding -> Bool
> :: Bech32Encoding -> Bech32Encoding -> Bool
$c> :: Bech32Encoding -> Bech32Encoding -> Bool
<= :: Bech32Encoding -> Bech32Encoding -> Bool
$c<= :: Bech32Encoding -> Bech32Encoding -> Bool
< :: Bech32Encoding -> Bech32Encoding -> Bool
$c< :: Bech32Encoding -> Bech32Encoding -> Bool
compare :: Bech32Encoding -> Bech32Encoding -> Ordering
$ccompare :: Bech32Encoding -> Bech32Encoding -> Ordering
Ord, Int -> Bech32Encoding
Bech32Encoding -> Int
Bech32Encoding -> [Bech32Encoding]
Bech32Encoding -> Bech32Encoding
Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
Bech32Encoding
-> Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Bech32Encoding
-> Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
$cenumFromThenTo :: Bech32Encoding
-> Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
enumFromTo :: Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
$cenumFromTo :: Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
enumFromThen :: Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
$cenumFromThen :: Bech32Encoding -> Bech32Encoding -> [Bech32Encoding]
enumFrom :: Bech32Encoding -> [Bech32Encoding]
$cenumFrom :: Bech32Encoding -> [Bech32Encoding]
fromEnum :: Bech32Encoding -> Int
$cfromEnum :: Bech32Encoding -> Int
toEnum :: Int -> Bech32Encoding
$ctoEnum :: Int -> Bech32Encoding
pred :: Bech32Encoding -> Bech32Encoding
$cpred :: Bech32Encoding -> Bech32Encoding
succ :: Bech32Encoding -> Bech32Encoding
$csucc :: Bech32Encoding -> Bech32Encoding
Enum)
type Bech32 = Text
type HRP = Text
type Data = [Word8]
(.>>.), (.<<.) :: Bits a => a -> Int -> a
.>>. :: forall a. Bits a => a -> Int -> a
(.>>.) = forall a. Bits a => a -> Int -> a
unsafeShiftR
.<<. :: forall a. Bits a => a -> Int -> a
(.<<.) = forall a. Bits a => a -> Int -> a
unsafeShiftL
newtype Word5
= UnsafeWord5 Word8
deriving (Word5 -> Word5 -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Word5 -> Word5 -> Bool
$c/= :: Word5 -> Word5 -> Bool
== :: Word5 -> Word5 -> Bool
$c== :: Word5 -> Word5 -> Bool
Eq, Eq Word5
Word5 -> Word5 -> Bool
Word5 -> Word5 -> Ordering
Word5 -> Word5 -> Word5
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Word5 -> Word5 -> Word5
$cmin :: Word5 -> Word5 -> Word5
max :: Word5 -> Word5 -> Word5
$cmax :: Word5 -> Word5 -> Word5
>= :: Word5 -> Word5 -> Bool
$c>= :: Word5 -> Word5 -> Bool
> :: Word5 -> Word5 -> Bool
$c> :: Word5 -> Word5 -> Bool
<= :: Word5 -> Word5 -> Bool
$c<= :: Word5 -> Word5 -> Bool
< :: Word5 -> Word5 -> Bool
$c< :: Word5 -> Word5 -> Bool
compare :: Word5 -> Word5 -> Ordering
$ccompare :: Word5 -> Word5 -> Ordering
Ord)
instance Ix Word5 where
range :: (Word5, Word5) -> [Word5]
range (UnsafeWord5 Word8
m, UnsafeWord5 Word8
n) = forall a b. (a -> b) -> [a] -> [b]
map Word8 -> Word5
UnsafeWord5 forall a b. (a -> b) -> a -> b
$ forall a. Ix a => (a, a) -> [a]
range (Word8
m, Word8
n)
index :: (Word5, Word5) -> Word5 -> Int
index (UnsafeWord5 Word8
m, UnsafeWord5 Word8
n) (UnsafeWord5 Word8
i) = forall a. Ix a => (a, a) -> a -> Int
index (Word8
m, Word8
n) Word8
i
inRange :: (Word5, Word5) -> Word5 -> Bool
inRange (Word5
m, Word5
n) Word5
i = Word5
m forall a. Ord a => a -> a -> Bool
<= Word5
i Bool -> Bool -> Bool
&& Word5
i forall a. Ord a => a -> a -> Bool
<= Word5
n
word5 :: Integral a => a -> Word5
word5 :: forall a. Integral a => a -> Word5
word5 a
x = Word8 -> Word5
UnsafeWord5 (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x forall a. Bits a => a -> a -> a
.&. Word8
31)
{-# INLINE word5 #-}
{-# SPECIALIZE INLINE word5 :: Word8 -> Word5 #-}
fromWord5 :: Num a => Word5 -> a
fromWord5 :: forall a. Num a => Word5 -> a
fromWord5 (UnsafeWord5 Word8
x) = forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
x
{-# INLINE fromWord5 #-}
{-# SPECIALIZE INLINE fromWord5 :: Word5 -> Word8 #-}
charset :: Array Word5 Char
charset :: Array Word5 Char
charset =
forall i e. Ix i => (i, i) -> [e] -> Array i e
listArray (Word8 -> Word5
UnsafeWord5 Word8
0, Word8 -> Word5
UnsafeWord5 Word8
31) [Char]
"qpzry9x8gf2tvdw0s3jn54khce6mua7l"
charsetMap :: Char -> Maybe Word5
charsetMap :: Char -> Maybe Word5
charsetMap Char
c
| forall a. Ix a => (a, a) -> a -> Bool
inRange (forall i e. Array i e -> (i, i)
bounds Array Char (Maybe Word5)
inv) Char
upperC = Array Char (Maybe Word5)
inv forall i e. Ix i => Array i e -> i -> e
! Char
upperC
| Bool
otherwise = forall a. Maybe a
Nothing
where
upperC :: Char
upperC = Char -> Char
toUpper Char
c
inv :: Array Char (Maybe Word5)
inv = forall i e. Ix i => (i, i) -> [e] -> Array i e
listArray (Char
'0', Char
'Z') (forall a. a -> [a]
repeat forall a. Maybe a
Nothing) forall i e. Ix i => Array i e -> [(i, e)] -> Array i e
// forall a b. (a -> b) -> [a] -> [b]
map forall {a}. (a, Char) -> (Char, Maybe a)
swap (forall i e. Ix i => Array i e -> [(i, e)]
assocs Array Word5 Char
charset)
swap :: (a, Char) -> (Char, Maybe a)
swap (a
a, Char
b) = (Char -> Char
toUpper Char
b, forall a. a -> Maybe a
Just a
a)
bech32Polymod :: [Word5] -> Word
bech32Polymod :: [Word5] -> Word
bech32Polymod [Word5]
values = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall {a}. (Bits a, Num a) => a -> Word5 -> a
go Word
1 [Word5]
values forall a. Bits a => a -> a -> a
.&. Word
0x3fffffff
where
go :: a -> Word5 -> a
go a
chk Word5
value =
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall a. Bits a => a -> a -> a
xor a
chk' [a
g | (a
g, Int
i) <- forall a b. [a] -> [b] -> [(a, b)]
zip [a]
generator [Int
25 ..], forall a. Bits a => a -> Int -> Bool
testBit a
chk Int
i]
where
generator :: [a]
generator = [a
0x3b6a57b2, a
0x26508e6d, a
0x1ea119fa, a
0x3d4233dd, a
0x2a1462b3]
chk' :: a
chk' = a
chk forall a. Bits a => a -> Int -> a
.<<. Int
5 forall a. Bits a => a -> a -> a
`xor` forall a. Num a => Word5 -> a
fromWord5 Word5
value
bech32HRPExpand :: HRP -> [Word5]
bech32HRPExpand :: Text -> [Word5]
bech32HRPExpand Text
hrp =
forall a b. (a -> b) -> [a] -> [b]
map (Word8 -> Word5
UnsafeWord5 forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Bits a => a -> Int -> a
.>>. Int
5)) [Word8]
hrpBytes
forall a. [a] -> [a] -> [a]
++ [Word8 -> Word5
UnsafeWord5 Word8
0]
forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map forall a. Integral a => a -> Word5
word5 [Word8]
hrpBytes
where
hrpBytes :: [Word8]
hrpBytes = ByteString -> [Word8]
B.unpack forall a b. (a -> b) -> a -> b
$ Text -> ByteString
E.encodeUtf8 Text
hrp
bech32Const :: Bech32Encoding -> Word
bech32Const :: Bech32Encoding -> Word
bech32Const Bech32Encoding
Bech32 = Word
0x00000001
bech32Const Bech32Encoding
Bech32m = Word
0x2bc830a3
bech32CreateChecksum :: Bech32Encoding -> HRP -> [Word5] -> [Word5]
bech32CreateChecksum :: Bech32Encoding -> Text -> [Word5] -> [Word5]
bech32CreateChecksum Bech32Encoding
enc Text
hrp [Word5]
dat = [forall a. Integral a => a -> Word5
word5 (Word
polymod forall a. Bits a => a -> Int -> a
.>>. Int
i) | Int
i <- [Int
25, Int
20 .. Int
0]]
where
values :: [Word5]
values = Text -> [Word5]
bech32HRPExpand Text
hrp forall a. [a] -> [a] -> [a]
++ [Word5]
dat
w5 :: [Word5]
w5 = [Word5]
values forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map Word8 -> Word5
UnsafeWord5 [Word8
0, Word8
0, Word8
0, Word8
0, Word8
0, Word8
0]
polymod :: Word
polymod = [Word5] -> Word
bech32Polymod [Word5]
w5 forall a. Bits a => a -> a -> a
`xor` Bech32Encoding -> Word
bech32Const Bech32Encoding
enc
bech32VerifyChecksum :: HRP -> [Word5] -> Maybe Bech32Encoding
bech32VerifyChecksum :: Text -> [Word5] -> Maybe Bech32Encoding
bech32VerifyChecksum Text
hrp [Word5]
dat =
let poly :: Word
poly = [Word5] -> Word
bech32Polymod (Text -> [Word5]
bech32HRPExpand Text
hrp forall a. [a] -> [a] -> [a]
++ [Word5]
dat)
in if
| Word
poly forall a. Eq a => a -> a -> Bool
== Bech32Encoding -> Word
bech32Const Bech32Encoding
Bech32 -> forall a. a -> Maybe a
Just Bech32Encoding
Bech32
| Word
poly forall a. Eq a => a -> a -> Bool
== Bech32Encoding -> Word
bech32Const Bech32Encoding
Bech32m -> forall a. a -> Maybe a
Just Bech32Encoding
Bech32m
| Bool
otherwise -> forall a. Maybe a
Nothing
maxBech32Length :: Int
maxBech32Length :: Int
maxBech32Length = Int
90
bech32Encode :: Bech32Encoding -> HRP -> [Word5] -> Maybe Bech32
bech32Encode :: Bech32Encoding -> Text -> [Word5] -> Maybe Text
bech32Encode Bech32Encoding
enc Text
hrp [Word5]
dat = do
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Text -> Bool
checkHRP Text
hrp
let dat' :: [Word5]
dat' = [Word5]
dat forall a. [a] -> [a] -> [a]
++ Bech32Encoding -> Text -> [Word5] -> [Word5]
bech32CreateChecksum Bech32Encoding
enc (Text -> Text
T.toLower Text
hrp) [Word5]
dat
rest :: [Char]
rest = forall a b. (a -> b) -> [a] -> [b]
map (Array Word5 Char
charset forall i e. Ix i => Array i e -> i -> e
!) [Word5]
dat'
result :: Text
result = [Text] -> Text
T.concat [Text -> Text
T.toLower Text
hrp, [Char] -> Text
T.pack [Char]
"1", [Char] -> Text
T.pack [Char]
rest]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Text -> Int
T.length Text
result forall a. Ord a => a -> a -> Bool
<= Int
maxBech32Length
forall (m :: * -> *) a. Monad m => a -> m a
return Text
result
checkHRP :: HRP -> Bool
checkHRP :: Text -> Bool
checkHRP Text
hrp =
Bool -> Bool
not (Text -> Bool
T.null Text
hrp)
Bool -> Bool -> Bool
&& (Char -> Bool) -> Text -> Bool
T.all (\Char
char -> Char
char forall a. Ord a => a -> a -> Bool
>= Char
'\x21' Bool -> Bool -> Bool
&& Char
char forall a. Ord a => a -> a -> Bool
<= Char
'\x7e') Text
hrp
bech32Decode :: Bech32 -> Maybe (Bech32Encoding, HRP, [Word5])
bech32Decode :: Text -> Maybe (Bech32Encoding, Text, [Word5])
bech32Decode Text
bech32 = do
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Text -> Int
T.length Text
bech32 forall a. Ord a => a -> a -> Bool
<= Int
maxBech32Length
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Text -> Text
T.toUpper Text
bech32 forall a. Eq a => a -> a -> Bool
== Text
bech32 Bool -> Bool -> Bool
|| Text
lowerBech32 forall a. Eq a => a -> a -> Bool
== Text
bech32
let (Text
hrp, Text
dat) = HasCallStack => Text -> Text -> (Text, Text)
T.breakOnEnd Text
"1" Text
lowerBech32
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Text -> Int
T.length Text
dat forall a. Ord a => a -> a -> Bool
>= Int
6
Text
hrp' <- Text -> Text -> Maybe Text
T.stripSuffix Text
"1" Text
hrp
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Text -> Bool
checkHRP Text
hrp'
[Word5]
dat' <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Char -> Maybe Word5
charsetMap forall a b. (a -> b) -> a -> b
$ Text -> [Char]
T.unpack Text
dat
Bech32Encoding
enc <- Text -> [Word5] -> Maybe Bech32Encoding
bech32VerifyChecksum Text
hrp' [Word5]
dat'
forall (m :: * -> *) a. Monad m => a -> m a
return (Bech32Encoding
enc, Text
hrp', forall a. Int -> [a] -> [a]
take (Text -> Int
T.length Text
dat forall a. Num a => a -> a -> a
- Int
6) [Word5]
dat')
where
lowerBech32 :: Text
lowerBech32 = Text -> Text
T.toLower Text
bech32
type Pad f = Int -> Int -> Word -> [[Word]] -> f [[Word]]
yesPadding :: Pad Identity
yesPadding :: Pad Identity
yesPadding Int
_ Int
0 Word
_ [[Word]]
result = forall (m :: * -> *) a. Monad m => a -> m a
return [[Word]]
result
yesPadding Int
_ Int
_ Word
padValue [[Word]]
result = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Word
padValue] forall a. a -> [a] -> [a]
: [[Word]]
result
{-# INLINE yesPadding #-}
noPadding :: Pad Maybe
noPadding :: Pad Maybe
noPadding Int
frombits Int
bits Word
padValue [[Word]]
result = do
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Int
bits forall a. Ord a => a -> a -> Bool
< Int
frombits Bool -> Bool -> Bool
&& Word
padValue forall a. Eq a => a -> a -> Bool
== Word
0
forall (m :: * -> *) a. Monad m => a -> m a
return [[Word]]
result
{-# INLINE noPadding #-}
convertBits :: Functor f => [Word] -> Int -> Int -> Pad f -> f [Word]
convertBits :: forall (f :: * -> *).
Functor f =>
[Word] -> Int -> Int -> Pad f -> f [Word]
convertBits [Word]
dat Int
frombits Int
tobits Pad f
pad = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
reverse forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall {a}.
Integral a =>
[a] -> Word -> Int -> [[Word]] -> f [[Word]]
go [Word]
dat Word
0 Int
0 []
where
go :: [a] -> Word -> Int -> [[Word]] -> f [[Word]]
go [] Word
acc Int
bits [[Word]]
result =
let padValue :: Word
padValue = (Word
acc forall a. Bits a => a -> Int -> a
.<<. (Int
tobits forall a. Num a => a -> a -> a
- Int
bits)) forall a. Bits a => a -> a -> a
.&. Word
maxv
in Pad f
pad Int
frombits Int
bits Word
padValue [[Word]]
result
go (a
value : [a]
dat') Word
acc Int
bits [[Word]]
result =
[a] -> Word -> Int -> [[Word]] -> f [[Word]]
go [a]
dat' Word
acc' (Int
bits' forall a. Integral a => a -> a -> a
`rem` Int
tobits) ([Word]
result' forall a. a -> [a] -> [a]
: [[Word]]
result)
where
acc' :: Word
acc' = (Word
acc forall a. Bits a => a -> Int -> a
.<<. Int
frombits) forall a. Bits a => a -> a -> a
.|. forall a b. (Integral a, Num b) => a -> b
fromIntegral a
value
bits' :: Int
bits' = Int
bits forall a. Num a => a -> a -> a
+ Int
frombits
result' :: [Word]
result' =
[ (Word
acc' forall a. Bits a => a -> Int -> a
.>>. Int
b) forall a. Bits a => a -> a -> a
.&. Word
maxv
| Int
b <- [Int
bits' forall a. Num a => a -> a -> a
- Int
tobits, Int
bits' forall a. Num a => a -> a -> a
- Int
2 forall a. Num a => a -> a -> a
* Int
tobits .. Int
0]
]
maxv :: Word
maxv = (Word
1 forall a. Bits a => a -> Int -> a
.<<. Int
tobits) forall a. Num a => a -> a -> a
- Word
1
{-# INLINE convertBits #-}
toBase32 :: [Word8] -> [Word5]
toBase32 :: [Word8] -> [Word5]
toBase32 [Word8]
dat =
forall a b. (a -> b) -> [a] -> [b]
map forall a. Integral a => a -> Word5
word5 forall a b. (a -> b) -> a -> b
$ forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *).
Functor f =>
[Word] -> Int -> Int -> Pad f -> f [Word]
convertBits (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (Integral a, Num b) => a -> b
fromIntegral [Word8]
dat) Int
8 Int
5 Pad Identity
yesPadding
toBase256 :: [Word5] -> Maybe [Word8]
toBase256 :: [Word5] -> Maybe [Word8]
toBase256 [Word5]
dat =
forall a b. (a -> b) -> [a] -> [b]
map forall a b. (Integral a, Num b) => a -> b
fromIntegral forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *).
Functor f =>
[Word] -> Int -> Int -> Pad f -> f [Word]
convertBits (forall a b. (a -> b) -> [a] -> [b]
map forall a. Num a => Word5 -> a
fromWord5 [Word5]
dat) Int
5 Int
8 Pad Maybe
noPadding
segwitCheck :: Bech32Encoding -> Word8 -> Data -> Bool
segwitCheck :: Bech32Encoding -> Word8 -> [Word8] -> Bool
segwitCheck Bech32Encoding
enc Word8
witver [Word8]
witprog =
Word8
witver forall a. Ord a => a -> a -> Bool
<= Word8
16
Bool -> Bool -> Bool
&& if Word8
witver forall a. Eq a => a -> a -> Bool
== Word8
0
then Bech32Encoding
enc forall a. Eq a => a -> a -> Bool
== Bech32Encoding
Bech32 Bool -> Bool -> Bool
&& (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
witprog forall a. Eq a => a -> a -> Bool
== Int
20 Bool -> Bool -> Bool
|| forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
witprog forall a. Eq a => a -> a -> Bool
== Int
32)
else Bech32Encoding
enc forall a. Eq a => a -> a -> Bool
== Bech32Encoding
Bech32m Bool -> Bool -> Bool
&& (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
witprog forall a. Ord a => a -> a -> Bool
>= Int
2 Bool -> Bool -> Bool
&& forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
witprog forall a. Ord a => a -> a -> Bool
<= Int
40)
segwitDecode :: HRP -> Bech32 -> Maybe (Word8, Data)
segwitDecode :: Text -> Text -> Maybe (Word8, [Word8])
segwitDecode Text
hrp Text
addr = do
(Bech32Encoding
enc, Text
hrp', [Word5]
dat) <- Text -> Maybe (Bech32Encoding, Text, [Word5])
bech32Decode Text
addr
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ (Text
hrp forall a. Eq a => a -> a -> Bool
== Text
hrp') Bool -> Bool -> Bool
&& Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Word5]
dat)
let (UnsafeWord5 Word8
witver : [Word5]
datBase32) = [Word5]
dat
[Word8]
decoded <- [Word5] -> Maybe [Word8]
toBase256 [Word5]
datBase32
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Bech32Encoding -> Word8 -> [Word8] -> Bool
segwitCheck Bech32Encoding
enc Word8
witver [Word8]
decoded
forall (m :: * -> *) a. Monad m => a -> m a
return (Word8
witver, [Word8]
decoded)
segwitEncode :: HRP -> Word8 -> Data -> Maybe Text
segwitEncode :: Text -> Word8 -> [Word8] -> Maybe Text
segwitEncode Text
hrp Word8
witver [Word8]
witprog = do
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Bech32Encoding -> Word8 -> [Word8] -> Bool
segwitCheck Bech32Encoding
enc Word8
witver [Word8]
witprog
Bech32Encoding -> Text -> [Word5] -> Maybe Text
bech32Encode Bech32Encoding
enc Text
hrp forall a b. (a -> b) -> a -> b
$ Word8 -> Word5
UnsafeWord5 Word8
witver forall a. a -> [a] -> [a]
: [Word8] -> [Word5]
toBase32 [Word8]
witprog
where
enc :: Bech32Encoding
enc = if Word8
witver forall a. Eq a => a -> a -> Bool
== Word8
0 then Bech32Encoding
Bech32 else Bech32Encoding
Bech32m