an atproto pds written in F# (.NET 9) 馃
pds
fsharp
giraffe
dotnet
atproto
1namespace PDSharp.Core
2
3open System
4open System.Text
5
6/// Minimal Base32 (RFC 4648 Lowercase)
7module Base32Encoding =
8 let private alphabet = "abcdefghijklmnopqrstuvwxyz234567"
9
10 let ToString (data : byte[]) : string =
11 if data.Length = 0 then
12 ""
13 else
14 let mutable i = 0
15 let mutable index = 0
16 let mutable digit = 0
17 let mutable currByte = 0
18 let mutable nextByte = 0
19 let sb = StringBuilder((data.Length + 7) * 8 / 5)
20
21 while i < data.Length do
22 currByte <- (int data.[i]) &&& 0xFF
23
24 if index > 3 then
25 if (i + 1) < data.Length then
26 nextByte <- (int data.[i + 1]) &&& 0xFF
27 else
28 nextByte <- 0
29
30 digit <- currByte &&& (0xFF >>> index)
31 index <- (index + 5) % 8
32 digit <- digit <<< index
33 digit <- digit ||| (nextByte >>> (8 - index))
34 i <- i + 1
35 else
36 digit <- currByte >>> 8 - (index + 5) &&& 0x1F
37 index <- (index + 5) % 8
38
39 if index = 0 then
40 i <- i + 1
41
42 sb.Append(alphabet.[digit]) |> ignore
43
44 sb.ToString()
45
46/// Basic CID implementation for AT Protocol (CIDv1 + dag-cbor + sha2-256)
47///
48/// Constants for ATProto defaults:
49/// - Version 1 (0x01)
50/// - Codec: dag-cbor (0x71)
51/// - Hash: sha2-256 (0x12) - Length 32 (0x20)
52[<Struct>]
53type Cid =
54 val Bytes : byte[]
55 new(bytes : byte[]) = { Bytes = bytes }
56
57 static member FromHash(hash : byte[]) =
58 if hash.Length <> 32 then
59 failwith "Hash must be 32 bytes (sha2-256)"
60
61 let cidBytes = Array.zeroCreate<byte> 36
62 cidBytes.[0] <- 0x01uy
63 cidBytes.[1] <- 0x71uy
64 cidBytes.[2] <- 0x12uy
65 cidBytes.[3] <- 0x20uy
66 Array.Copy(hash, 0, cidBytes, 4, 32)
67 Cid cidBytes
68
69 override this.ToString() =
70 "b" + Base32Encoding.ToString(this.Bytes)