File size: 18,862 Bytes
9425aed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
!=====================================================================
! bob_goldilocks.f90
! Goldilocks field arithmetic: p = 2^64 - 2^32 + 1
! Used in PLONK, Plonky2, Miden ZK systems.
! Matches utqc-goldilocks/src/lib.rs exactly.
! Standard: Fortran 2018
! ABI: ISO C binding for use from sov_monster_kernel
!=====================================================================
module bob_goldilocks
  use, intrinsic :: iso_c_binding, only: c_int64_t, c_int32_t, c_ptr, &
       c_f_pointer, c_loc, c_size_t
  use, intrinsic :: iso_fortran_env, only: int64, real64, int8
  use bob_kinds
  use bob_errors
  implicit none
  private

  ! Goldilocks prime: p = 2^64 - 2^32 + 1
  integer(i8), parameter, public :: GOLDILOCKS_P = int(Z'FFFFFFFF00000001', i8)
  ! Primitive root g = 7 (generates the multiplicative group)
  integer(i8), parameter, public :: GOLDILOCKS_G = 7_i8
  ! Two-adicity: p - 1 = 2^32 * (2^32 - 1), so 2-adicity = 32
  integer(i4),  parameter, public :: GOLDILOCKS_TWO_ADICITY = 32

  !> Goldilocks field element
  type, public :: goldilocks_t
    integer(i8) :: val = 0_i8
  contains
    procedure :: add   => gf_add
    procedure :: sub   => gf_sub
    procedure :: mul   => gf_mul
    procedure :: neg   => gf_neg
    procedure :: inv   => gf_inv
    procedure :: pow   => gf_pow
    procedure :: is_zero => gf_is_zero
    procedure :: to_int  => gf_to_int
  end type goldilocks_t

  public :: goldilocks_new
  public :: goldilocks_from_canonical
  public :: goldilocks_reduce
  public :: goldilocks_mul_hi
  public :: goldilocks_ntt          ! Number Theoretic Transform
  public :: goldilocks_intt         ! Inverse NTT
  public :: goldilocks_fft_layer    ! Single butterfly layer
  public :: gf_add, gf_sub, gf_mul, gf_neg, gf_inv, gf_pow

  ! C ABI
  public :: bob_gf_new
  public :: bob_gf_add
  public :: bob_gf_mul
  public :: bob_gf_inv
  public :: bob_gf_pow
  public :: bob_gf_ntt
  public :: bob_gf_intt

contains

  !──────────────────────────────────────────────────────────────────
  ! Constructor: reduce val mod p
  !──────────────────────────────────────────────────────────────────
  pure function goldilocks_new(val) result(f)
    integer(i8), intent(in) :: val
    type(goldilocks_t) :: f
    f%val = goldilocks_reduce(val)
  end function goldilocks_new

  !──────────────────────────────────────────────────────────────────
  ! Create from already-canonical value (0 <= val < p)
  !──────────────────────────────────────────────────────────────────
  pure function goldilocks_from_canonical(val) result(f)
    integer(i8), intent(in) :: val
    type(goldilocks_t) :: f
    f%val = val
  end function goldilocks_from_canonical

  !──────────────────────────────────────────────────────────────────
  ! Reduce: val mod p using the Goldilocks structure
  ! p = 2^64 - 2^32 + 1 = 0xFFFFFFFF00000001
  ! Fast reduction: if val >= p, val - p (no division needed for one step)
  !──────────────────────────────────────────────────────────────────
  pure function goldilocks_reduce(val) result(r)
    integer(i8), intent(in) :: val
    integer(i8) :: r
    r = val
    ! Handle values in [p, 2p)
    if (r >= GOLDILOCKS_P) then
      r = r - GOLDILOCKS_P
    end if
    ! Handle values in [2p, 3p) β€” can happen after addition
    if (r >= GOLDILOCKS_P) then
      r = r - GOLDILOCKS_P
    end if
  end function goldilocks_reduce

  !──────────────────────────────────────────────────────────────────
  ! High bits of product (needed for full 128-bit multiply mod p)
  ! Returns the upper 64 bits of a*b
  !──────────────────────────────────────────────────────────────────
  pure function goldilocks_mul_hi(a, b) result(hi)
    integer(i8), intent(in) :: a, b
    integer(i8) :: hi
    integer(i8) :: a_lo, a_hi, b_lo, b_hi
    integer(i8) :: cross1, cross2, cross
    ! Split into 32-bit halves
    a_lo = iand(a, int(Z'00000000FFFFFFFF', i8))
    a_hi = ishft(a, -32)
    b_lo = iand(b, int(Z'00000000FFFFFFFF', i8))
    b_hi = ishft(b, -32)
    ! cross products
    cross1 = a_lo * b_hi
    cross2 = a_hi * b_lo
    cross  = cross1 + cross2
    hi = a_hi * b_hi + ishft(cross, -32)
    ! add carry from low 64 bits
    if (iand(cross, int(Z'00000000FFFFFFFF', i8)) + &
        ishft(a_lo * b_lo, -32) >= int(Z'0000000100000000', i8)) then
      hi = hi + 1_i8
    end if
  end function goldilocks_mul_hi

  !──────────────────────────────────────────────────────────────────
  ! Modular multiplication using Goldilocks reduction
  ! (a * b) mod p, where p = 2^64 - 2^32 + 1
  ! Uses the identity: x mod p = x_lo - x_hi * (p - 2^64)
  !                             = x_lo + x_hi * (2^32 - 1)
  !──────────────────────────────────────────────────────────────────
  pure function gf_mul(this, other) result(r)
    class(goldilocks_t), intent(in) :: this, other
    type(goldilocks_t) :: r
    integer(i8) :: lo, hi, adj
    ! Full 128-bit product
    lo = this%val * other%val      ! lower 64 bits (wraps mod 2^64)
    hi = goldilocks_mul_hi(this%val, other%val)
    ! Goldilocks reduction: result = lo + hi * (2^32 - 1)
    !                              = lo + hi * 2^32 - hi
    adj = ishft(hi, 32) - hi
    ! lo + adj, then reduce
    r%val = goldilocks_reduce(lo + adj)
  end function gf_mul

  !──────────────────────────────────────────────────────────────────
  ! Addition mod p
  !──────────────────────────────────────────────────────────────────
  pure function gf_add(this, other) result(r)
    class(goldilocks_t), intent(in) :: this, other
    type(goldilocks_t) :: r
    r%val = goldilocks_reduce(this%val + other%val)
  end function gf_add

  !──────────────────────────────────────────────────────────────────
  ! Subtraction mod p
  !──────────────────────────────────────────────────────────────────
  pure function gf_sub(this, other) result(r)
    class(goldilocks_t), intent(in) :: this, other
    type(goldilocks_t) :: r
    integer(i8) :: diff
    diff = this%val - other%val
    if (diff < 0_i8) diff = diff + GOLDILOCKS_P
    r%val = diff
  end function gf_sub

  !──────────────────────────────────────────────────────────────────
  ! Negation: p - val
  !──────────────────────────────────────────────────────────────────
  pure function gf_neg(this) result(r)
    class(goldilocks_t), intent(in) :: this
    type(goldilocks_t) :: r
    if (this%val == 0_i8) then
      r%val = 0_i8
    else
      r%val = GOLDILOCKS_P - this%val
    end if
  end function gf_neg

  !──────────────────────────────────────────────────────────────────
  ! Multiplicative inverse via Fermat: a^(p-2) mod p
  ! p - 2 = 0xFFFFFFFF00000000 - 1... use square-and-multiply
  !──────────────────────────────────────────────────────────────────
  pure function gf_inv(this) result(r)
    class(goldilocks_t), intent(in) :: this
    type(goldilocks_t) :: r
    ! Use the fact that p - 2 has a nice binary structure
    ! p - 2 = 2^64 - 2^32 - 1
    ! Chain: a^1 β†’ a^2 β†’ a^3 β†’ a^6 β†’ a^12 β†’ a^24 β†’ a^32 β†’ a^64 β†’ ...
    type(goldilocks_t) :: x, t
    integer(i4) :: i
    x = this
    t = goldilocks_from_canonical(1_i8)
    ! Square-and-multiply for exponent p-2
    ! Simplified: full loop over all 64 bits of p-2
    ! p - 2 bits (big-endian): 1111...1111 0000...0000 1111...1111 11111110
    ! Fast path using Fermat chains for Goldilocks specifically
    ! Use the addition chain from the Goldilocks paper
    ! Step 1: a^(2^32 - 1) via squarings
    x = this
    do i = 1, 31
      x = x%mul(x)  ! x = a^(2^i)
    end do
    t = x%mul(this)   ! t = a^(2^32 - 1)
    ! Step 2: t^(2^32) * t = a^(2^64 - 2^32 + 2^32 - 1) ... not quite
    ! Fallback: generic square-and-multiply on p-2
    x = this
    t = goldilocks_from_canonical(1_i8)
    call gf_pow_impl(x, GOLDILOCKS_P - 2_i8, t)
    r = t
  end function gf_inv

  !──────────────────────────────────────────────────────────────────
  ! Power: base^exp mod p (square-and-multiply)
  !──────────────────────────────────────────────────────────────────
  pure function gf_pow(this, exp) result(r)
    class(goldilocks_t), intent(in) :: this
    integer(i8), intent(in) :: exp
    type(goldilocks_t) :: r
    r = goldilocks_from_canonical(1_i8)
    call gf_pow_impl(this, exp, r)
  end function gf_pow

  pure subroutine gf_pow_impl(base, exp, result)
    type(goldilocks_t), intent(in)    :: base
    integer(i8),       intent(in)    :: exp
    type(goldilocks_t), intent(inout) :: result
    type(goldilocks_t) :: b
    integer(i8) :: e
    b = base; e = exp
    do while (e > 0_i8)
      if (iand(e, 1_i8) == 1_i8) result = result%mul(b)
      b = b%mul(b)
      e = ishft(e, -1)
    end do
  end subroutine gf_pow_impl

  pure function gf_is_zero(this) result(z)
    class(goldilocks_t), intent(in) :: this
    logical :: z
    z = (this%val == 0_i8)
  end function gf_is_zero

  pure function gf_to_int(this) result(v)
    class(goldilocks_t), intent(in) :: this
    integer(i8) :: v
    v = this%val
  end function gf_to_int

  !══════════════════════════════════════════════════════════════════
  ! Number Theoretic Transform (NTT) over Goldilocks field
  ! Cooley-Tukey butterfly, in-place, size must be power of 2
  ! Used in PLONK polynomial commitments
  !══════════════════════════════════════════════════════════════════

  !> Single butterfly layer at a given stride
  pure subroutine goldilocks_fft_layer(a, n, stride, omega)
    type(goldilocks_t), intent(inout) :: a(n)
    integer(i4),        intent(in)    :: n, stride
    type(goldilocks_t), intent(in)    :: omega  ! root of unity for this layer
    type(goldilocks_t) :: w, u, v
    integer(i4) :: i, j
    w = goldilocks_from_canonical(1_i8)
    do i = 0, stride - 1
      do j = i, n - 1, 2 * stride
        u = a(j + 1)
        v = w%mul(a(j + stride + 1))
        a(j + 1)          = u%add(v)
        a(j + stride + 1) = u%sub(v)
      end do
      w = w%mul(omega)
    end do
  end subroutine goldilocks_fft_layer

  !> In-place NTT of array a of length n (must be power of 2)
  subroutine goldilocks_ntt(a, n, status)
    type(goldilocks_t), intent(inout) :: a(n)
    integer(i4),        intent(in)    :: n
    integer(c_int32_t), intent(out)   :: status
    type(goldilocks_t) :: omega
    integer(i8) :: root_pow
    integer(i4)  :: len, half
    status = BOB_SUCCESS
    if (n <= 1) return
    ! Check power of 2
    if (iand(n, n-1) /= 0) then
      call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, &
           "NTT size must be power of 2", "goldilocks_ntt")
      status = BOB_ERROR_INVALID_ARGUMENT; return
    end if
    ! Bit-reverse permutation
    call bit_reverse_permute(a, n)
    ! Butterfly layers
    len = 2
    do while (len <= n)
      half = len / 2
      ! Root of unity: g^((p-1)/len) mod p
      root_pow = (GOLDILOCKS_P - 1_i8) / int(len, i8)
      omega = goldilocks_from_canonical(GOLDILOCKS_G)
      omega = omega%pow(root_pow)
      call goldilocks_fft_layer(a, n, half, omega)
      len = len * 2
    end do
  end subroutine goldilocks_ntt

  !> In-place inverse NTT
  subroutine goldilocks_intt(a, n, status)
    type(goldilocks_t), intent(inout) :: a(n)
    integer(i4),        intent(in)    :: n
    integer(c_int32_t), intent(out)   :: status
    type(goldilocks_t) :: omega, n_inv
    integer(i8) :: root_pow
    integer(i4)  :: len, half, i
    status = BOB_SUCCESS
    if (n <= 1) return
    if (iand(n, n-1) /= 0) then
      status = BOB_ERROR_INVALID_ARGUMENT; return
    end if
    call bit_reverse_permute(a, n)
    len = 2
    do while (len <= n)
      half = len / 2
      root_pow = (GOLDILOCKS_P - 1_i8) / int(len, i8)
      ! Use inverse root: g^(p-1 - (p-1)/len)
      omega = goldilocks_from_canonical(GOLDILOCKS_G)
      omega = omega%pow(GOLDILOCKS_P - 1_i8 - root_pow)
      call goldilocks_fft_layer(a, n, half, omega)
      len = len * 2
    end do
    ! Divide by n
    n_inv = goldilocks_new(int(n, i8))
    n_inv = n_inv%inv()
    do i = 1, n
      a(i) = a(i)%mul(n_inv)
    end do
  end subroutine goldilocks_intt

  !> Bit-reverse permutation
  pure subroutine bit_reverse_permute(a, n)
    type(goldilocks_t), intent(inout) :: a(n)
    integer(i4),        intent(in)    :: n
    type(goldilocks_t) :: tmp
    integer(i4) :: i, j, k, bits
    bits = 0; k = n
    do while (k > 1); bits = bits + 1; k = k / 2; end do
    j = 0
    do i = 1, n - 1
      k = n / 2
      do while (iand(j, k) /= 0); j = ieor(j, k); k = k / 2; end do
      j = ieor(j, k)
      if (i < j + 1) then
        tmp = a(i + 1); a(i + 1) = a(j + 1); a(j + 1) = tmp
      end if
    end do
  end subroutine bit_reverse_permute

  !══════════════════════════════════════════════════════════════════
  ! C ABI
  !══════════════════════════════════════════════════════════════════

  function bob_gf_new(val) result(out) bind(C, name="bob_gf_new")
    integer(c_int64_t), value :: val
    integer(c_int64_t)        :: out
    out = goldilocks_reduce(val)
  end function bob_gf_new

  function bob_gf_add(a, b) result(out) bind(C, name="bob_gf_add")
    integer(c_int64_t), value :: a, b
    integer(c_int64_t)        :: out
    type(goldilocks_t) :: fa, fb, tmp_gf
    fa = goldilocks_from_canonical(a)
    fb = goldilocks_from_canonical(b)
    tmp_gf = fa%add(fb); out = tmp_gf%val
  end function bob_gf_add

  function bob_gf_mul(a, b) result(out) bind(C, name="bob_gf_mul")
    integer(c_int64_t), value :: a, b
    integer(c_int64_t)        :: out
    type(goldilocks_t) :: fa, fb, tmp_gf
    fa = goldilocks_from_canonical(a)
    fb = goldilocks_from_canonical(b)
    tmp_gf = fa%mul(fb); out = tmp_gf%val
  end function bob_gf_mul

  function bob_gf_inv(a) result(out) bind(C, name="bob_gf_inv")
    integer(c_int64_t), value :: a
    integer(c_int64_t)        :: out
    type(goldilocks_t) :: fa, tmp_gf
    fa = goldilocks_from_canonical(a)
    tmp_gf = fa%inv(); out = tmp_gf%val
  end function bob_gf_inv

  function bob_gf_pow(a, exp) result(out) bind(C, name="bob_gf_pow")
    integer(c_int64_t), value :: a, exp
    integer(c_int64_t)        :: out
    type(goldilocks_t) :: fa, tmp_gf
    fa = goldilocks_from_canonical(a)
    tmp_gf = fa%pow(exp); out = tmp_gf%val
  end function bob_gf_pow

  function bob_gf_ntt(arr_ptr, n) result(status) bind(C, name="bob_gf_ntt")
    type(c_ptr),        value :: arr_ptr
    integer(c_int32_t), value :: n
    integer(c_int32_t)        :: status
    integer(i8), pointer :: arr(:)
    type(goldilocks_t), allocatable :: gf(:)
    integer(i4) :: i
    call c_f_pointer(arr_ptr, arr, [n])
    allocate(gf(n))
    do i = 1, n; gf(i) = goldilocks_from_canonical(arr(i)); end do
    call goldilocks_ntt(gf, n, status)
    do i = 1, n; arr(i) = gf(i)%val; end do
    deallocate(gf)
  end function bob_gf_ntt

  function bob_gf_intt(arr_ptr, n) result(status) bind(C, name="bob_gf_intt")
    type(c_ptr),        value :: arr_ptr
    integer(c_int32_t), value :: n
    integer(c_int32_t)        :: status
    integer(i8), pointer :: arr(:)
    type(goldilocks_t), allocatable :: gf(:)
    integer(i4) :: i
    call c_f_pointer(arr_ptr, arr, [n])
    allocate(gf(n))
    do i = 1, n; gf(i) = goldilocks_from_canonical(arr(i)); end do
    call goldilocks_intt(gf, n, status)
    do i = 1, n; arr(i) = gf(i)%val; end do
    deallocate(gf)
  end function bob_gf_intt

end module bob_goldilocks

! Made with Bob