@@ -2,7 +2,7 @@ module Parser
2
2
3
3
using ... ElGamal: ElGamalRow
4
4
using CryptoGroups. Curves: a, b, field, gx, gy
5
- using CryptoGroups: PGroup, ECGroup, Group, value, concretize_type, spec, generator, name, ECPoint, modulus, order
5
+ using CryptoGroups: PGroup, ECGroup, Group, value, concretize_type, spec, generator, name, ECPoint, modulus, order, octet
6
6
using CryptoPRG. Verificatum: HashSpec
7
7
import CryptoGroups. Fields: bitlength # TODO : import -> using
8
8
using CryptoGroups. Utils: int2octet, @check
@@ -13,16 +13,16 @@ import Base.==
13
13
tobig (x) = parse (BigInt, bytes2hex (reverse (x)), base= 16 )
14
14
interpret (:: Type{BigInt} , x:: Vector{UInt8} ) = tobig (reverse (x))
15
15
16
- function interpret (:: Type{T} , x:: Vector{UInt8} ) where T <: Integer
17
-
16
+ function interpret (:: Type{T} , x:: AbstractVector{UInt8} ) where T <: Integer
18
17
L = bitlength (T) ÷ 8
19
- y = UInt8[zeros (UInt8, L - length (x))... , x... ]
20
-
21
- r = reinterpret (T, reverse (y))[1 ]
22
- return r
18
+ result = zero (T)
19
+ for i in 1 : min (length (x), L)
20
+ result |= T (x[length (x)- i+ 1 ]) << (8 (i- 1 )) # @inbounds
21
+ end
22
+ return result
23
23
end
24
24
25
- function int2bytes ( x:: Integer )
25
+ function interpret ( :: Type{Vector{UInt8}} , x:: BigInt )
26
26
27
27
@check x > 0
28
28
@@ -31,10 +31,9 @@ function int2bytes(x::Integer)
31
31
hex = string (" 0" , hex)
32
32
end
33
33
34
- return reverse ( hex2bytes (hex) )
34
+ return hex2bytes (hex)
35
35
end
36
36
37
- interpret (:: Type{Vector{UInt8}} , x:: BigInt ) = reverse (int2bytes (x))
38
37
interpret (:: Type{Vector{UInt8}} , x:: Integer ) = reverse (reinterpret (UInt8, [x])) # Number of bytes are useful for construction for bytes.
39
38
40
39
function interpret (:: Type{Vector{T}} , 𝐫:: Vector{UInt8} , N:: Int ) where T <: Integer
@@ -72,75 +71,104 @@ Base.push!(n::Node, y) = push!(n.x, y)
72
71
73
72
toint (x) = reinterpret (UInt32, x[4 : - 1 : 1 ])[1 ] # ## TOREMOVE
74
73
75
- function parseb (x)
76
-
77
- if x[1 ] == LEAF
78
-
79
- L = interpret (UInt32, x[2 : 5 ])
80
-
81
- bytes = x[6 : 5 + L]
82
- leaf = Leaf (bytes)
83
-
84
- if length (x) == L + 5
85
- rest = []
86
- else
87
- rest = x[L+ 6 : end ]
88
- end
89
-
90
- return leaf, rest
91
74
92
- elseif x[2 ] == NODE
75
+ # Add position tracking to avoid array slicing
76
+ mutable struct BinaryParser
77
+ data:: Vector{UInt8}
78
+ pos:: Int
79
+ end
93
80
94
- N = interpret (UInt32, x[2 : 5 ])
81
+ function read_uint32! (parser:: BinaryParser )
82
+ val = interpret (UInt32, @view parser. data[parser. pos: parser. pos+ 3 ])
83
+ parser. pos += 4
84
+ return val
85
+ end
95
86
96
- rest = x[6 : end ]
87
+ function read_bytes! (parser:: BinaryParser , len:: Integer )
88
+ bytes = @view parser. data[parser. pos: parser. pos+ len- 1 ]
89
+ parser. pos += len
90
+ return bytes
91
+ end
97
92
93
+ function parseb! (parser:: BinaryParser )
94
+ marker = parser. data[parser. pos]
95
+ parser. pos += 1
96
+
97
+ if marker == LEAF
98
+ L = read_uint32! (parser)
99
+ bytes = read_bytes! (parser, L)
100
+ return Leaf (bytes)
101
+ elseif marker == NODE
102
+ N = read_uint32! (parser)
98
103
node = Node ()
99
-
100
- for i in 1 : N
101
- head, tail = parseb (rest)
102
- push! (node, head)
103
- rest = tail
104
+ sizehint! (node. x, N) # Pre-allocate space for children
105
+ for _ in 1 : N
106
+ child = parseb! (parser)
107
+ push! (node, child)
104
108
end
105
-
106
- return node, rest
109
+ return node
110
+ else
111
+ throw (ArgumentError (" Invalid marker byte: $marker " ))
107
112
end
108
113
end
109
114
115
+ # Main entry point that maintains the same interface
116
+ function parseb (x:: Vector{UInt8} )
117
+ parser = BinaryParser (x, 1 )
118
+ tree = parseb! (parser)
119
+ remaining = if parser. pos <= length (x)
120
+ @view x[parser. pos: end ]
121
+ else
122
+ UInt8[]
123
+ end
124
+ return tree, remaining
125
+ end
110
126
111
127
decode (x:: Vector{UInt8} ) = parseb (x)[1 ]
112
128
decode (x:: AbstractString ) = decode (hex2bytes (replace (x, " " => " " ))) # I could have optional arguments here as well
113
129
114
-
115
- function tobin (leaf:: Leaf )
116
-
117
- N = UInt32 (length (leaf. x))
118
-
119
- Nbin = interpret (Vector{UInt8}, N)
120
- bin = UInt8[LEAF, Nbin... , leaf. x... ]
121
-
122
- return bin
130
+ # Helper function to write UInt32 in correct byte order
131
+ function write_uint32! (io:: IO , n:: UInt32 )
132
+ # Write length in little-endian format
133
+ bytes = reinterpret (UInt8, [n])
134
+ # Reverse bytes to match expected format
135
+ write (io, reverse (bytes))
123
136
end
124
137
125
- function tobin (node:: Node )
138
+ function encode! (io:: IO , leaf:: Leaf )
139
+ # Write type marker for leaf (01)
140
+ write (io, UInt8 (0x01 ))
126
141
127
- N = UInt32 ( length (node . x))
128
- Nbin = interpret (Vector{UInt8}, N )
142
+ # Write length of data
143
+ write_uint32! (io, UInt32 ( length (leaf . x)) )
129
144
130
- data = UInt8[]
145
+ # Write data directly
146
+ write (io, leaf. x)
147
+ end
131
148
132
- for n in node. x
133
- b = tobin (n)
134
- append! (data, b)
149
+ function encode! (io:: IO , node:: Node )
150
+ # Write type marker for node (00)
151
+ write (io, UInt8 (0x00 ))
152
+
153
+ # Write number of children
154
+ write_uint32! (io, UInt32 (length (node. x)))
155
+
156
+ # Write all child nodes directly
157
+ for child in node. x
158
+ encode! (io, child)
135
159
end
160
+ end
136
161
137
- bin = UInt8[NODE, Nbin... , data... ]
162
+ # Generic dispatch for Tree type
163
+ encode! (io:: IO , tree:: Tree ) = encode! (io, tree)
138
164
139
- return bin
165
+ # Optional convenience method that returns the encoded bytes
166
+ function encode (tree:: Tree )
167
+ io = IOBuffer ()
168
+ encode! (io, tree)
169
+ take! (io)
140
170
end
141
171
142
- encode (x:: Tree ) = tobin (x)
143
-
144
172
convert (:: Type{T} , x:: Leaf ) where T <: Integer = interpret (T, x. x)
145
173
146
174
function convert (:: Type{String} , x:: Leaf )
@@ -168,25 +196,36 @@ function Leaf(x::Signed)
168
196
end
169
197
170
198
Leaf (x:: Unsigned ) = Leaf (interpret (Vector{UInt8}, x))
171
-
172
199
173
- function Leaf (x:: Integer , k:: Integer )
174
-
200
+ function interpret! (result:: Vector{UInt8} , k:: Integer , x:: Integer )
175
201
if x == 0
176
-
177
- return Leaf (zeros (UInt8, k))
178
-
179
- else
180
- leaf = Leaf (x)
181
-
182
- N = findfirst (x -> x != UInt8 (0 ), leaf. x)
183
- bytes = leaf. x[N: end ]
184
- pad = k - length (bytes)
185
-
186
- return newleaf = Leaf (UInt8[zeros (UInt8, pad)... ,bytes... ])
202
+ fill! (result, 0x00 )
203
+ return 0
204
+ end
205
+
206
+ hex = string (x, base= 16 )
207
+ bytes_needed = (length (hex) + 1 ) ÷ 2
208
+
209
+ # Fill padding zeros if needed
210
+ if k > bytes_needed
211
+ fill! (view (result, 1 : k- bytes_needed), 0x00 )
212
+ end
213
+
214
+ # Ensure even length for hex string
215
+ if mod (length (hex), 2 ) != 0
216
+ hex = string (" 0" , hex)
187
217
end
218
+
219
+ hex2bytes! (view (result, k- bytes_needed+ 1 : k), hex)
220
+
221
+ return bytes_needed
188
222
end
189
223
224
+ function Leaf (x:: Integer , k:: Integer )
225
+ result = Vector {UInt8} (undef, k)
226
+ interpret! (result, k, x)
227
+ return Leaf (result)
228
+ end
190
229
191
230
function Leaf (x:: AbstractString )
192
231
bytes = Vector {UInt8} (x)
@@ -213,10 +252,8 @@ function Node(x::Tuple; L=nothing)
213
252
return node
214
253
end
215
254
216
-
217
255
# ########################### COMPOSITE TYPE PARSING ############################
218
256
219
-
220
257
function convert (:: Type{Vector{G}} , x:: Node ; allow_one= false ) where G <: Group
221
258
return G[convert (G, i; allow_one) for i in x. x]
222
259
end
@@ -236,19 +273,62 @@ Tree(x::PGroup; L = bitlength(x)) = Leaf(value(x), div(L + 1, 8, RoundUp))
236
273
# Probably I will need to replace
237
274
convert (:: Type{G} , x:: Leaf ; allow_one= false ) where G <: PGroup = convert (G, convert (BigInt, x); allow_one)
238
275
239
- # ## Note that only PrimeCurves are supported.
240
- convert (:: Type{G} , x:: Node ; allow_one= false ) where G <: ECGroup = convert (G, convert (Tuple{BigInt, BigInt}, x); allow_one)
241
- convert (:: Type{ECGroup{P}} , x:: Node ; allow_one= false ) where P <: ECPoint = convert (ECGroup{P}, convert (Tuple{BigInt, BigInt}, x); allow_one)
276
+ # Perhaps I could also use a let here
277
+ # It could be made threaad local
278
+ const EC_BUFFER = Vector {UInt8} (undef, 1000 ) # We can make it also thread local
279
+ function convert (:: Type{ECGroup{P}} , x:: Node ; allow_one= false ) where P <: ECPoint
280
+
281
+ L = bitlength (field (P))
282
+ nbytes_field = cld (L, 8 )
283
+
284
+ x_bytes = @view x[1 ]. x[end - (nbytes_field- 1 ): end ]
285
+ y_bytes = @view x[2 ]. x[end - (nbytes_field- 1 ): end ]
286
+
287
+ if all (iszero, x_bytes) && all (iszero, y_bytes)
288
+ point_bytes = UInt8[0x00 ]
289
+ else
290
+ # buffer = Vector{UInt8}(undef, 1 + 2*nbytes_field)
291
+ EC_BUFFER[1 ] = 0x04
292
+ @inbounds copyto! (@view (EC_BUFFER[2 : nbytes_field+ 1 ]), x_bytes)
293
+ @inbounds copyto! (@view (EC_BUFFER[nbytes_field+ 2 : 2 nbytes_field+ 1 ]), y_bytes)
294
+
295
+ point_bytes = @view EC_BUFFER[1 : 2 nbytes_field+ 1 ]
296
+ # point_bytes = UInt8[0x04; x_bytes; y_bytes]
297
+ end
242
298
299
+ return convert (ECGroup{P}, point_bytes; allow_one)
300
+ end
243
301
244
302
function Tree (g:: G ; L = bitlength (G)) where G <: ECGroup
303
+
304
+ nbytes_field = cld (L, 8 ) # Using cld instead of div(x, y, RoundUp)
305
+ nbytes_spec = cld (L + 1 , 8 )
245
306
246
- gxleaf = Leaf (value (gx (g)), div (L + 1 , 8 , RoundUp))
247
- gyleaf = Leaf (value (gy (g)), div (L + 1 , 8 , RoundUp))
307
+ bytes = octet (g)
308
+
309
+ if iszero (bytes[1 ])
310
+
311
+ leaf = Leaf (zeros (UInt8, nbytes_spec))
312
+ return Tree ((leaf, leaf))
313
+
314
+ end
315
+
316
+ @views x_bytes = bytes[2 : nbytes_field + 1 ]
317
+ @views y_bytes = bytes[nbytes_field + 2 : end ]
248
318
249
- gtree = Tree ((gxleaf, gyleaf))
319
+ if nbytes_spec == nbytes_field
250
320
251
- return gtree
321
+ gxleaf = Leaf (x_bytes)
322
+ gyleaf = Leaf (y_bytes)
323
+
324
+ elseif nbytes_spec == nbytes_field + 1 # This is such an unfortunate oversight in the specification
325
+
326
+ gxleaf = Leaf (UInt8[0x00 ; x_bytes])
327
+ gyleaf = Leaf (UInt8[0x00 ; y_bytes])
328
+
329
+ end
330
+
331
+ return Tree ((gxleaf, gyleaf))
252
332
end
253
333
254
334
function Tree (x:: Vector{<:Group} )
363
443
364
444
function convert (:: Type{Vector{ElGamalRow{G, N}}} , tree:: Node ; allow_one= false ) where {G <: Group , N}
365
445
366
- # 𝐚 = convert(NTuple{N, Vector{G}}, tree[1]; allow_one)
367
- # 𝐛 = convert(NTuple{N, Vector{G}}, tree[2]; allow_one)
368
-
369
446
𝐚 = ntuple (n -> convert (Vector{G}, tree[1 ][n]; allow_one), N)
370
447
𝐛 = ntuple (n -> convert (Vector{G}, tree[2 ][n]; allow_one), N)
371
448
@@ -384,14 +461,11 @@ function convert(::Type{ElGamalRow{G, 1}}, tree::Node; allow_one=false) where G
384
461
return ElGamalRow (a, b)
385
462
end
386
463
387
-
388
464
convert (:: Type{NTuple{N, G}} , tree:: Node ; allow_one= false ) where {G <: Group , N} = ntuple (n -> convert (G, tree[n]; allow_one), N)
389
465
390
-
391
466
convert (:: Type{NTuple{N, BigInt}} , tree:: Node ) where N = ntuple (n -> convert (BigInt, tree[n]), N)
392
467
convert (:: Type{NTuple{1, BigInt}} , tree:: Leaf ) = tuple (convert (BigInt, tree))
393
468
394
-
395
469
function convert (:: Type{ElGamalRow{G, N}} , tree:: Node ; allow_one= false ) where {G <: Group , N}
396
470
397
471
a_tree, b_tree = tree. x
0 commit comments