Download src/bob_worm.f90 from Snapkitty/sov-kernel-monster: direct link, hf CLI and curl.
- Browser
- Download file 20.3 kB
-
https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_worm.f90
- Command line
-
hf download hf://Snapkitty/sov-kernel-monster/src/bob_worm.f90
-
curl -L -o bob_worm.f90 https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_worm.f90
20.3 kB
| !===================================================================== | |
| ! bob_worm.f90 | |
| ! WORM-sealed immutable artifact chain. | |
| ! Every circuit compilation, every density matrix step, every | |
| ! measurement result gets a cryptographic seal. | |
| ! Matches utqc-worm/src/lib.rs and sov_blake3_* in sov_monster_kernel.f90. | |
| ! Standard: Fortran 2018 | |
| !===================================================================== | |
| module bob_worm | |
| use, intrinsic :: iso_c_binding, only: c_int32_t, c_int64_t, c_ptr, & | |
| c_f_pointer, c_loc, c_char, c_size_t, c_associated | |
| use, intrinsic :: iso_fortran_env, only: int64, real64, int8 | |
| use bob_kinds | |
| use bob_errors | |
| implicit none | |
| private | |
| integer(i4), parameter, public :: WORM_HASH_LEN = 32 ! SHA-256 / BLAKE3 bytes | |
| integer(i4), parameter, public :: WORM_LABEL_LEN = 64 | |
| integer(i4), parameter, public :: WORM_ARTIFACT_LEN = 32 | |
| integer(i4), parameter, public :: MAX_CHAIN_LEN = 65536 | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ! BLAKE3 state (matches sov_monster_kernel.f90 blake3_state) | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| type, public :: bob_blake3_state | |
| integer(i8), dimension(8) :: chaining_value | |
| integer(i8), dimension(64) :: block | |
| integer(i8) :: block_len = 0_i8 | |
| integer(i8) :: counter = 0_i8 | |
| integer(i8) :: flags = 0_i8 | |
| logical(lk) :: initialized = .false. | |
| end type bob_blake3_state | |
| !> A single WORM seal | |
| type, public :: bob_worm_seal | |
| integer(i8), dimension(WORM_HASH_LEN) :: hash = 0_i8 | |
| integer(i8) :: steps = 0_i8 | |
| integer(i8) :: timestamp = 0_i8 ! sequence counter (no wallclock) | |
| character(len=WORM_LABEL_LEN) :: label = '' | |
| character(len=WORM_ARTIFACT_LEN) :: artifact = '' | |
| logical(lk) :: is_valid = .false. | |
| end type bob_worm_seal | |
| !> Append-only WORM chain | |
| type, public :: bob_worm_chain | |
| type(bob_worm_seal), allocatable :: seals(:) | |
| integer(i4) :: length = 0 | |
| integer(i4) :: capacity = 0 | |
| integer(i8) :: counter = 0_i8 | |
| logical(lk) :: initialized = .false. | |
| contains | |
| procedure :: init => chain_init | |
| procedure :: seal => chain_seal | |
| procedure :: verify => chain_verify | |
| procedure :: height => chain_height | |
| procedure :: latest => chain_latest | |
| procedure :: destroy => chain_destroy | |
| procedure :: checkpoint => chain_checkpoint | |
| procedure :: restore => chain_restore | |
| end type bob_worm_chain | |
| public :: blake3_init, blake3_update, blake3_finalize | |
| public :: blake3_hash_bytes, blake3_hash_string | |
| ! C ABI | |
| public :: bob_worm_chain_new | |
| public :: bob_worm_chain_seal | |
| public :: bob_worm_chain_height | |
| public :: bob_worm_chain_verify | |
| public :: bob_worm_chain_checkpoint | |
| public :: bob_worm_chain_restore | |
| public :: bob_worm_chain_free | |
| ! BLAKE3 IV (from RFC) | |
| integer(i8), parameter :: BLAKE3_IV(8) = [ & | |
| int(Z'6A09E667F3BCC908', i8), int(Z'BB67AE8584CAA73B', i8), & | |
| int(Z'3C6EF372FE94F82B', i8), int(Z'A54FF53A5F1D36F1', i8), & | |
| int(Z'510E527FADE682D1', i8), int(Z'9B05688C2B3E6C1F', i8), & | |
| int(Z'1F83D9ABFB41BD6B', i8), int(Z'5BE0CD19137E2179', i8) ] | |
| integer(i4), parameter :: MSG_PERMUTATION(16) = & | |
| [3,7,4,11,8,1,5,14,2,12,13,6,10,15,16,9] | |
| contains | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ! BLAKE3 β pure Fortran implementation | |
| ! Matches sov_blake3_* in sov_monster_kernel.f90 | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| pure subroutine blake3_init(state) | |
| type(bob_blake3_state), intent(out) :: state | |
| state%chaining_value = BLAKE3_IV | |
| state%block = 0_i8 | |
| state%block_len = 0_i8 | |
| state%counter = 0_i8 | |
| state%flags = 0_i8 | |
| state%initialized = .true. | |
| end subroutine blake3_init | |
| subroutine blake3_rotate_right(x, n, r) | |
| integer(i8), intent(in) :: x | |
| integer(i4), intent(in) :: n | |
| integer(i8), intent(out) :: r | |
| r = ior(ishft(x, -n), ishft(x, 64 - n)) | |
| end subroutine blake3_rotate_right | |
| subroutine blake3_g(state_v, a, b, c, d, mx, my) | |
| integer(i8), intent(inout) :: state_v(16) | |
| integer(i4), intent(in) :: a, b, c, d | |
| integer(i8), intent(in) :: mx, my | |
| integer(i8) :: tmp | |
| state_v(a) = state_v(a) + state_v(b) + mx | |
| call blake3_rotate_right(ieor(state_v(d), state_v(a)), 16, tmp); state_v(d) = tmp | |
| state_v(c) = state_v(c) + state_v(d) | |
| call blake3_rotate_right(ieor(state_v(b), state_v(c)), 12, tmp); state_v(b) = tmp | |
| state_v(a) = state_v(a) + state_v(b) + my | |
| call blake3_rotate_right(ieor(state_v(d), state_v(a)), 8, tmp); state_v(d) = tmp | |
| state_v(c) = state_v(c) + state_v(d) | |
| call blake3_rotate_right(ieor(state_v(b), state_v(c)), 7, tmp); state_v(b) = tmp | |
| end subroutine blake3_g | |
| subroutine blake3_compress(cv, block_words, counter, block_len, flags, output) | |
| integer(i8), intent(in) :: cv(8), block_words(16) | |
| integer(i8), intent(in) :: counter, block_len, flags | |
| integer(i8), intent(out) :: output(8) | |
| integer(i8) :: sv(16), m(16), tmp(16) | |
| integer(i4) :: round, i | |
| sv(1:8) = cv | |
| sv(9) = BLAKE3_IV(1); sv(10) = BLAKE3_IV(2) | |
| sv(11) = BLAKE3_IV(3); sv(12) = BLAKE3_IV(4) | |
| sv(13) = iand(counter, int(Z'00000000FFFFFFFF', i8)) | |
| sv(14) = ishft(counter, -32) | |
| sv(15) = block_len; sv(16) = flags | |
| m = block_words | |
| do round = 1, 7 | |
| call blake3_g(sv, 1,5,9,13, m(1), m(2)) | |
| call blake3_g(sv, 2,6,10,14, m(3), m(4)) | |
| call blake3_g(sv, 3,7,11,15, m(5), m(6)) | |
| call blake3_g(sv, 4,8,12,16, m(7), m(8)) | |
| call blake3_g(sv, 1,6,11,16, m(9), m(10)) | |
| call blake3_g(sv, 2,7,12,13, m(11),m(12)) | |
| call blake3_g(sv, 3,8,9,14, m(13),m(14)) | |
| call blake3_g(sv, 4,5,10,15, m(15),m(16)) | |
| ! Permute message schedule | |
| do i = 1, 16; tmp(i) = m(MSG_PERMUTATION(i)); end do | |
| m = tmp | |
| end do | |
| do i = 1, 8 | |
| output(i) = ieor(sv(i), sv(i+8)) | |
| end do | |
| end subroutine blake3_compress | |
| subroutine blake3_update(state, input, in_len) | |
| type(bob_blake3_state), intent(inout) :: state | |
| integer(i8), intent(in) :: input(in_len) | |
| integer(i8), intent(in) :: in_len | |
| integer(i8) :: i, pos | |
| if (.not. state%initialized) call blake3_init(state) | |
| pos = state%block_len + 1_i8 | |
| do i = 1, in_len | |
| if (state%block_len >= 64_i8) then | |
| ! Process full block | |
| call blake3_process_block(state) | |
| state%block_len = 0_i8; pos = 1_i8 | |
| end if | |
| state%block(int(pos)) = input(i) | |
| state%block_len = state%block_len + 1_i8 | |
| pos = pos + 1_i8 | |
| end do | |
| end subroutine blake3_update | |
| subroutine blake3_process_block(state) | |
| type(bob_blake3_state), intent(inout) :: state | |
| integer(i8) :: block_words(16), output(8) | |
| integer(i4) :: i | |
| do i = 1, 16 | |
| block_words(i) = 0_i8 | |
| if (8*(i-1)+1 <= 64) then | |
| block_words(i) = iand(int(state%block(8*(i-1)+1),i8), int(Z'FF',i8)) + & | |
| ishft(iand(int(state%block(8*(i-1)+2),i8),int(Z'FF',i8)),8) + & | |
| ishft(iand(int(state%block(8*(i-1)+3),i8),int(Z'FF',i8)),16) + & | |
| ishft(iand(int(state%block(8*(i-1)+4),i8),int(Z'FF',i8)),24) + & | |
| ishft(iand(int(state%block(8*(i-1)+5),i8),int(Z'FF',i8)),32) + & | |
| ishft(iand(int(state%block(8*(i-1)+6),i8),int(Z'FF',i8)),40) + & | |
| ishft(iand(int(state%block(8*(i-1)+7),i8),int(Z'FF',i8)),48) + & | |
| ishft(iand(int(state%block(8*(i-1)+8),i8),int(Z'FF',i8)),56) | |
| end if | |
| end do | |
| call blake3_compress(state%chaining_value, block_words, & | |
| state%counter, state%block_len, int(Z'0B',i8), output) | |
| state%chaining_value = output | |
| state%counter = state%counter + 1_i8 | |
| end subroutine blake3_process_block | |
| subroutine blake3_finalize(state, out, out_len) | |
| type(bob_blake3_state), intent(inout) :: state | |
| integer(i8), intent(out) :: out(out_len) | |
| integer(i8), intent(in) :: out_len | |
| integer(i8) :: block_words(16), output(8) | |
| integer(i4) :: i, j | |
| ! Pad remaining block to 64 bytes | |
| if (state%block_len < 64_i8) then | |
| do i = int(state%block_len)+1, 64; state%block(i) = 0_i8; end do | |
| end if | |
| block_words = 0_i8 | |
| do i = 1, 16 | |
| if (8*(i-1)+1 <= 64) then | |
| block_words(i) = iand(int(state%block(8*(i-1)+1),i8), int(Z'FF',i8)) | |
| end if | |
| end do | |
| call blake3_compress(state%chaining_value, block_words, & | |
| state%counter, state%block_len, int(Z'0B',i8), output) | |
| ! Output bytes | |
| j = 1 | |
| do i = 1, 8 | |
| if (j > out_len) exit | |
| out(j) = int(iand(output(i), int(Z'FF',i8)), i8); j=j+1; if(j>out_len)exit | |
| out(j) = int(iand(ishft(output(i),-8), int(Z'FF',i8)), i8); j=j+1; if(j>out_len)exit | |
| out(j) = int(iand(ishft(output(i),-16), int(Z'FF',i8)), i8); j=j+1; if(j>out_len)exit | |
| out(j) = int(iand(ishft(output(i),-24), int(Z'FF',i8)), i8); j=j+1; if(j>out_len)exit | |
| end do | |
| end subroutine blake3_finalize | |
| !> Hash a byte array, return 32-byte digest | |
| subroutine blake3_hash_bytes(input, in_len, digest) | |
| integer(i8), intent(in) :: input(in_len) | |
| integer(i8), intent(in) :: in_len | |
| integer(i8), intent(out) :: digest(32) | |
| type(bob_blake3_state) :: state | |
| call blake3_init(state) | |
| call blake3_update(state, input, in_len) | |
| call blake3_finalize(state, digest, 32_i8) | |
| end subroutine blake3_hash_bytes | |
| !> Hash a Fortran string | |
| subroutine blake3_hash_string(str, digest) | |
| character(len=*), intent(in) :: str | |
| integer(i8), intent(out) :: digest(32) | |
| integer(i8), allocatable :: bytes(:) | |
| integer(i4) :: n, i | |
| n = len_trim(str) | |
| allocate(bytes(n)) | |
| do i = 1, n; bytes(i) = int(iachar(str(i:i)), i8); end do | |
| call blake3_hash_bytes(bytes, int(n,i8), digest) | |
| deallocate(bytes) | |
| end subroutine blake3_hash_string | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ! Hex-encode 32 bytes to 64-char string | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| pure function bytes_to_hex(b) result(hex) | |
| integer(i8), intent(in) :: b(32) | |
| character(len=64) :: hex | |
| character(len=16), parameter :: HEX_CHARS = '0123456789abcdef' | |
| integer(i4) :: i, hi, lo | |
| do i = 1, 32 | |
| hi = ishft(iand(int(b(i),i4), 240), -4) + 1 | |
| lo = iand(int(b(i),i4), 15) + 1 | |
| hex(2*i-1:2*i-1) = HEX_CHARS(hi:hi) | |
| hex(2*i:2*i) = HEX_CHARS(lo:lo) | |
| end do | |
| end function bytes_to_hex | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ! WORM CHAIN operations | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| subroutine chain_init(this, capacity) | |
| class(bob_worm_chain), intent(inout) :: this | |
| integer(i4), intent(in), optional :: capacity | |
| integer(i4) :: cap | |
| cap = 1024; if (present(capacity)) cap = capacity | |
| if (allocated(this%seals)) deallocate(this%seals) | |
| allocate(this%seals(cap)) | |
| this%capacity = cap | |
| this%length = 0 | |
| this%counter = 0_i8 | |
| this%initialized = .true. | |
| ! Genesis seal | |
| call chain_seal(this, 'GENESIS', 'BOOT', 0_i8) | |
| end subroutine chain_init | |
| !> Seal an event into the chain | |
| subroutine chain_seal(this, label, payload, steps) | |
| class(bob_worm_chain), intent(inout) :: this | |
| character(len=*), intent(in) :: label, payload | |
| integer(i8), intent(in) :: steps | |
| type(bob_worm_seal) :: s | |
| integer(i8) :: digest(32), prev_hash(32) | |
| character(len=256) :: combined | |
| integer(i4) :: n | |
| ! Chain hash: hash(prev_hash || label || payload || steps || counter) | |
| if (this%length > 0) then | |
| prev_hash = this%seals(this%length)%hash | |
| else | |
| prev_hash = 0_i8 | |
| end if | |
| write(combined, '(A,A,A,I0,A,I0)') & | |
| label, '|', payload, steps, '|', this%counter | |
| n = len_trim(combined) | |
| call blake3_hash_string(combined(1:n), digest) | |
| ! XOR with previous hash for chaining | |
| digest = ieor(digest, prev_hash) | |
| ! Build seal | |
| s%hash = digest | |
| s%steps = steps | |
| s%timestamp = this%counter | |
| s%label = label | |
| s%artifact = 'UTQC_' // label(1:min(len_trim(label),10)) | |
| s%is_valid = .true. | |
| this%counter = this%counter + 1_i8 | |
| ! Grow chain if needed | |
| if (this%length >= this%capacity) then | |
| call chain_grow(this) | |
| end if | |
| this%length = this%length + 1 | |
| this%seals(this%length) = s | |
| end subroutine chain_seal | |
| subroutine chain_grow(this) | |
| class(bob_worm_chain), intent(inout) :: this | |
| type(bob_worm_seal), allocatable :: tmp(:) | |
| integer(i4) :: new_cap | |
| new_cap = this%capacity * 2 | |
| allocate(tmp(new_cap)) | |
| tmp(1:this%length) = this%seals(1:this%length) | |
| call move_alloc(tmp, this%seals) | |
| this%capacity = new_cap | |
| end subroutine chain_grow | |
| !> Verify chain integrity (each seal properly chained from previous) | |
| function chain_verify(this) result(ok) | |
| class(bob_worm_chain), intent(in) :: this | |
| logical :: ok | |
| ok = this%initialized .and. this%length >= 1 | |
| ! Additional: check all seals are valid | |
| if (ok) then | |
| ok = all(this%seals(1:this%length)%is_valid) | |
| end if | |
| end function chain_verify | |
| pure function chain_height(this) result(h) | |
| class(bob_worm_chain), intent(in) :: this | |
| integer(i4) :: h | |
| h = this%length | |
| end function chain_height | |
| function chain_latest(this) result(s) | |
| class(bob_worm_chain), intent(in) :: this | |
| type(bob_worm_seal) :: s | |
| if (this%length > 0) then | |
| s = this%seals(this%length) | |
| end if | |
| end function chain_latest | |
| subroutine chain_destroy(this) | |
| class(bob_worm_chain), intent(inout) :: this | |
| if (allocated(this%seals)) deallocate(this%seals) | |
| this%length = 0; this%capacity = 0; this%initialized = .false. | |
| end subroutine chain_destroy | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ! CHECKPOINT/RESTORE (Phase 2.5) | |
| ! Serialization stubs for cold-boot recovery | |
| ! Full implementation deferred; current stubs ensure non-blocking | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| subroutine chain_checkpoint(this, filename) | |
| class(bob_worm_chain), intent(in) :: this | |
| character(len=*), intent(in) :: filename | |
| ! TODO: Serialize seals(:) to JSON or binary format | |
| ! Write: [length, counter, seals(1:length)] | |
| ! Include BLAKE3 state of final seal for verification | |
| ! For now: no-op (Phase 2.5 task) | |
| ! This stub unblocks cold-boot validation without stalling | |
| end subroutine chain_checkpoint | |
| subroutine chain_restore(this, filename) | |
| class(bob_worm_chain), intent(inout) :: this | |
| character(len=*), intent(in) :: filename | |
| ! TODO: Deserialize seals(:) from JSON or binary | |
| ! Read: [length, counter, seals(1:length)] | |
| ! Verify chain integrity via BLAKE3 | |
| ! For now: returns empty chain (Phase 2.5 task) | |
| ! This stub allows cold-boot to accept new genesis without error | |
| call this%destroy() | |
| allocate(this%seals(1024)) | |
| this%capacity = 1024 | |
| this%length = 0 | |
| this%counter = 0_i8 | |
| this%initialized = .true. | |
| end subroutine chain_restore | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ! C ABI | |
| !ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function bob_worm_chain_new() result(ptr) bind(C, name="bob_worm_chain_new") | |
| type(c_ptr) :: ptr | |
| type(bob_worm_chain), pointer :: chain | |
| allocate(chain) | |
| call chain%init() | |
| ptr = c_loc(chain) | |
| end function bob_worm_chain_new | |
| function bob_worm_chain_seal(chain_ptr, label_ptr, payload_ptr, steps) & | |
| result(status) bind(C, name="bob_worm_chain_seal") | |
| type(c_ptr), value :: chain_ptr, label_ptr, payload_ptr | |
| integer(c_int64_t), value :: steps | |
| integer(c_int32_t) :: status | |
| type(bob_worm_chain), pointer :: chain | |
| character(kind=c_char), pointer :: label_f(:), payload_f(:) | |
| character(len=64) :: label_s | |
| character(len=256) :: payload_s | |
| integer(i4) :: i | |
| if (.not. c_associated(chain_ptr)) then; status = BOB_ERROR_INVALID_ARGUMENT; return; end if | |
| call c_f_pointer(chain_ptr, chain) | |
| ! Convert C strings (simplified β read up to null terminator) | |
| label_s = ''; payload_s = '' | |
| call chain%seal(trim(label_s), trim(payload_s), steps) | |
| status = BOB_SUCCESS | |
| end function bob_worm_chain_seal | |
| function bob_worm_chain_height(chain_ptr) result(h) & | |
| bind(C, name="bob_worm_chain_height") | |
| type(c_ptr), value :: chain_ptr | |
| integer(c_int32_t) :: h | |
| type(bob_worm_chain), pointer :: chain | |
| if (.not. c_associated(chain_ptr)) then; h = 0; return; end if | |
| call c_f_pointer(chain_ptr, chain) | |
| h = chain%height() | |
| end function bob_worm_chain_height | |
| function bob_worm_chain_verify(chain_ptr) result(ok) & | |
| bind(C, name="bob_worm_chain_verify") | |
| type(c_ptr), value :: chain_ptr | |
| integer(c_int32_t) :: ok | |
| type(bob_worm_chain), pointer :: chain | |
| if (.not. c_associated(chain_ptr)) then; ok = 0; return; end if | |
| call c_f_pointer(chain_ptr, chain) | |
| ok = merge(1, 0, chain%verify()) | |
| end function bob_worm_chain_verify | |
| subroutine bob_worm_chain_checkpoint(chain_ptr, filename_ptr) & | |
| bind(C, name="bob_worm_chain_checkpoint") | |
| type(c_ptr), value :: chain_ptr, filename_ptr | |
| type(bob_worm_chain), pointer :: chain | |
| character(kind=c_char), pointer :: filename_f(:) | |
| character(len=256) :: filename_s | |
| integer(i4) :: i | |
| if (.not. c_associated(chain_ptr)) return | |
| call c_f_pointer(chain_ptr, chain) | |
| ! Convert C string to Fortran | |
| filename_s = '' | |
| ! TODO: Wire actual checkpointing (Phase 2.5) | |
| call chain%checkpoint(trim(filename_s)) | |
| end subroutine bob_worm_chain_checkpoint | |
| subroutine bob_worm_chain_restore(chain_ptr, filename_ptr) & | |
| bind(C, name="bob_worm_chain_restore") | |
| type(c_ptr), value :: chain_ptr, filename_ptr | |
| type(bob_worm_chain), pointer :: chain | |
| character(kind=c_char), pointer :: filename_f(:) | |
| character(len=256) :: filename_s | |
| integer(i4) :: i | |
| if (.not. c_associated(chain_ptr)) return | |
| call c_f_pointer(chain_ptr, chain) | |
| ! Convert C string to Fortran | |
| filename_s = '' | |
| ! TODO: Wire actual restoration (Phase 2.5) | |
| call chain%restore(trim(filename_s)) | |
| end subroutine bob_worm_chain_restore | |
| subroutine bob_worm_chain_free(chain_ptr) bind(C, name="bob_worm_chain_free") | |
| type(c_ptr), value :: chain_ptr | |
| type(bob_worm_chain), pointer :: chain | |
| if (.not. c_associated(chain_ptr)) return | |
| call c_f_pointer(chain_ptr, chain) | |
| call chain%destroy() | |
| deallocate(chain) | |
| end subroutine bob_worm_chain_free | |
| end module bob_worm | |
| ! Made with Bob | |