Download src/bob_goldilocks.f90 from Snapkitty/sov-kernel-monster: direct link, hf CLI and curl.
- Browser
- Download file 18.9 kB
-
https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_goldilocks.f90
- Command line
-
hf download hf://Snapkitty/sov-kernel-monster/src/bob_goldilocks.f90
-
curl -L -o bob_goldilocks.f90 https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_goldilocks.f90
18.9 kB
| !===================================================================== | |
| ! 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 | |