Recent

Author Topic: Bitcoin Bech32 implementation  (Read 1638 times)

Luiz Claudio

  • New member
  • *
  • Posts: 8
Bitcoin Bech32 implementation
« on: June 22, 2023, 05:27:02 pm »
Does anyone have a Bitcoin Bech32 implementation with address validation that they would like to share here?

I've seen examples of address validation in:

C++
C#
Java
VB.NET

However, no Delphi/Free Pascal implementation was found.

Luiz Claudio

  • New member
  • *
  • Posts: 8
Re: Bitcoin Bech32 implementation
« Reply #1 on: June 28, 2023, 03:53:10 pm »
Here is a Delphi code translated from F# by ChatGPT and a small change:

Code: Pascal  [Select][+][-]
  1. uses
  2.    Generics.Collections;
  3.  
  4. type
  5.   TForm1 = class(TForm)
  6.     Button1: TButton;
  7.     procedure Button1Click(Sender: TObject);
  8.   private
  9.     { Private declarations }
  10.   public
  11.     { Public declarations }
  12.   end;
  13.  
  14. const
  15.   Charset = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
  16.   Generator: array[0..4] of UInt32 = ($3B6A57B2, $26508E6D, $1EA119FA, $3D4233DD, $2A1462B3);
  17.  
  18. var
  19.   Form1: TForm1;
  20.  
  21. implementation
  22.  
  23. {$R *.dfm}
  24.  
  25. function Bech32Polymod(const values: array of UInt32): UInt32;
  26. var
  27.   chk, b, i, j: UInt32;
  28. begin
  29.   chk := 1;
  30.   for i := 0 to Length(values) - 1 do
  31.   begin
  32.     b := chk shr 25;
  33.     chk := ((chk and $1FFFFFF) shl 5) xor values[i];
  34.     for j := 0 to 4 do
  35.     begin
  36.       if (b shr j) and 1 = 1 then
  37.         chk := chk xor Generator[j];
  38.     end;
  39.   end;
  40.   Result := chk;
  41. end;
  42.  
  43. function HrpExpand(const hrp: string): TList<UInt32>;
  44. var
  45.   i: Integer;
  46. begin
  47.   Result := TList<UInt32>.Create;
  48.   for i := 1 to Length(hrp) do
  49.     Result.Add(Ord(hrp[i]) shr 5);
  50.   Result.Add(0);
  51.   for i := 1 to Length(hrp) do
  52.     Result.Add(Ord(hrp[i]) and 31);
  53. end;
  54.  
  55. function VerifyChecksum(const hrp: string; const data: TList<UInt32>): Boolean;
  56. var
  57.   lhrpExpand: TList<UInt32>;
  58. begin
  59.   lhrpExpand := hrpExpand(hrp);
  60.   lhrpExpand.AddRange(data.ToArray);
  61.   Result := Bech32Polymod(lhrpExpand.ToArray) = 1;
  62. end;
  63.  
  64. function Decode(const str: string): TPair<string, TList<UInt32>>;
  65. var
  66.   lastOneIndex: Integer;
  67.   hrp, data: string;
  68.   dataValues: TList<UInt32>;
  69.   i, v: Integer;
  70. begin
  71.   lastOneIndex := Pos('1', str);
  72.   hrp := Copy(str, 1, lastOneIndex - 1);
  73.   data := Copy(str, lastOneIndex + 1, Length(str));
  74.   dataValues := TList<UInt32>.Create;
  75.  
  76.   for i := 1 to Length(data) do
  77.   begin
  78.     v := Pos(data[i], Charset);
  79.     if v = 0 then
  80.       raise Exception.Create('invalid bech32 address')
  81.     else
  82.       dataValues.Add(v - 1);
  83.   end;
  84.  
  85.   if VerifyChecksum(hrp, dataValues) then
  86.     Result := TPair<string, TList<UInt32>>.Create(hrp, dataValues)
  87.   else
  88.     raise Exception.Create('invalid bech32 address');
  89.  
  90.   ShowMessage('Valid.');
  91. end;
  92.  
  93. procedure TForm1.Button1Click(Sender: TObject);
  94. begin
  95.   Decode('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4');
  96.   Decode('abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw');
  97. end;
  98.  

Thaddy

  • Hero Member
  • *****
  • Posts: 18666
  • Jungle wars. And failing health it seems.
Re: Bitcoin Bech32 implementation
« Reply #2 on: June 28, 2023, 04:43:16 pm »
That code assumes {$mode delphi} btw. And it leaks memory like hell...
Can probably all be fixed for mode objfpc, but the memory leaks are not that easy to fix, because of the creates inside the functions. It also leaks like hell in Delphi itself...
Bad code is not finished... But except for the leaks, the results are OK.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Luiz Claudio

  • New member
  • *
  • Posts: 8
Re: Bitcoin Bech32 implementation
« Reply #3 on: June 28, 2023, 07:06:07 pm »
That code assumes {$mode delphi} btw. And it leaks memory like hell...
Can probably all be fixed for mode objfpc, but the memory leaks are not that easy to fix, because of the creates inside the functions. It also leaks like hell in Delphi itself...
Bad code is not finished... But except for the leaks, the results are OK.

Any suggestion to fix leaks memory will welcome.

af0815

  • Hero Member
  • *****
  • Posts: 1407
Re: Bitcoin Bech32 implementation
« Reply #4 on: June 28, 2023, 08:03:04 pm »
Any suggestion to fix leaks memory will welcome.
(SCNR) Ask ChatGPT for a fix, because it have written leaky code
regards
Andreas

Luiz Claudio

  • New member
  • *
  • Posts: 8
Re: Bitcoin Bech32 implementation
« Reply #5 on: June 28, 2023, 09:52:54 pm »
Any suggestion to fix leaks memory will welcome.
(SCNR) Ask ChatGPT for a fix, because it have written leaky code

FIXED:

Code: Pascal  [Select][+][-]
  1. uses
  2.   Generics.Collections;
  3.  
  4. type
  5.   TForm1 = class(TForm)
  6.     Button1: TButton;
  7.     procedure Button1Click(Sender: TObject);
  8.   private
  9.     { Private declarations }
  10.   public
  11.     { Public declarations }
  12.   end;
  13.  
  14. const
  15.   Charset = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
  16.   Generator: array[0..4] of UInt32 = ($3B6A57B2, $26508E6D, $1EA119FA, $3D4233DD, $2A1462B3);
  17.  
  18. var
  19.   Form1: TForm1;
  20.  
  21. implementation
  22.  
  23. {$R *.dfm}
  24.  
  25. function Polymod(const Values: array of UInt32): UInt32;
  26. var
  27.   Chk, B, I, J: UInt32;
  28. begin
  29.   Chk := 1;
  30.   for I := 0 to Length(Values) - 1 do
  31.   begin
  32.     B := Chk shr 25;
  33.     Chk := ((Chk and $1FFFFFF) shl 5) xor Values[I];
  34.     for J := 0 to 4 do
  35.     begin
  36.       if (B shr J) and 1 = 1 then
  37.         Chk := Chk xor Generator[J];
  38.     end;
  39.   end;
  40.   Result := Chk;
  41. end;
  42.  
  43. function ExpandHrp(const Hrp: string): TList<UInt32>;
  44. var
  45.   I: Integer;
  46. begin
  47.   Result := TList<UInt32>.Create;
  48.   for I := 1 to Length(Hrp) do
  49.     Result.Add(Ord(Hrp[I]) shr 5);
  50.   Result.Add(0);
  51.   for I := 1 to Length(Hrp) do
  52.     Result.Add(Ord(Hrp[I]) and 31);
  53. end;
  54.  
  55. function VerifyChecksum(const Hrp: string; const Data: TList<UInt32>): Boolean;
  56. var
  57.   HrpExpand: TList<UInt32>;
  58. begin
  59.   HrpExpand := ExpandHrp(Hrp);
  60.   try
  61.     HrpExpand.AddRange(Data.ToArray);
  62.     Result := Polymod(HrpExpand.ToArray) = 1;
  63.   finally
  64.     HrpExpand.Free;
  65.   end;
  66. end;
  67.  
  68. function IsBech32Address(const Str: string): Boolean;
  69. var
  70.   LastOneIndex: Integer;
  71.   Hrp, Data: string;
  72.   DataValues: TList<UInt32>;
  73.   I, V: Integer;
  74. begin
  75.   LastOneIndex := Pos('1', Str);
  76.   Hrp := Copy(Str, 1, LastOneIndex - 1);
  77.   Data := Copy(Str, LastOneIndex + 1, Length(Str));
  78.   DataValues := TList<UInt32>.Create;
  79.   try
  80.     for I := 1 to Length(Data) do
  81.     begin
  82.       V := Pos(Data[I], Charset);
  83.       if V = 0 then
  84.         raise Exception.Create('invalid bech32 address')
  85.       else
  86.         DataValues.Add(V - 1);
  87.     end;
  88.     if VerifyChecksum(Hrp, DataValues) then
  89.       Result := True
  90.     else
  91.       raise Exception.Create('invalid bech32 address');
  92.   finally
  93.     DataValues.Free;
  94.   end;
  95. end;
  96.  
  97. procedure TForm1.Button1Click(Sender: TObject);
  98. begin
  99.   if IsBech32Address('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4') then
  100.     ShowMessage('Valid.');
  101. end;
  102.  
  103. end.
  104.  
« Last Edit: June 28, 2023, 09:59:09 pm by Luiz Claudio »

 

TinyPortal © 2005-2018