offset: MACRO
; I want to keep myself sane
if _NARG > 1
ld a, \2
endc
add a, LOW(\1)
ld LOW(\1), a
jr nc, .no_carry_\@
inc HIGH(\1)
.no_carry_\@
ENDM
CalculateSHA1:
; in: hl: pointer to data, a: length (bytes)
; out: hl = hl + 64 pointing to hash, all other regs clobbered, initial data buffer clobbered
; returns carry iif a > 55 (since this would require implementing proper blocking)
; prereq's: a <= 55, hl points to an 84-byte buffer initialized with the data
cp 55
ccf
ret c
push hl
; pad the block
ld c, a
offset hl
ld a, $80
ld [hli], a
ld a, c
sub 62
ld b, a
xor a
jr .padding_loop_check
.padding_loop
ld [hli], a
.padding_loop_check
inc b
jr nz, .padding_loop
ld a, c
add a, a
add a, a
add a, a
ld b, a
sbc a
and 1
ld [hli], a
ld a, b
ld [hli], a
; initialize the registers
ld b, 20
ld de, .initialization_data
.initialization_loop
ld a, [de]
inc de
ld [hli], a
dec b
jr nz, .initialization_loop
pop hl
; 80 iterations of operations
xor a
.iteration_loop
call .combine_states_and_constant
push hl
push af
and $f
add a, a
add a, a
offset hl
call .add_word
pop af
pop hl
push af
call .update_states
pop af
cp $40
call c, .update_buffer_word
inc a
cp $50
jr c, .iteration_loop
; add the results to the initialization data
offset hl, $40
push hl
xor a
.final_addition_loop
push af
call .load_word
dec hl
dec hl
dec hl
dec hl
pop af
push af
push hl
ld hl, .initialization_data
add a, a
add a, a
offset hl
call .add_word
pop hl
call .store_word
pop af
inc a
cp 5
jr c, .final_addition_loop
; and we're done!
pop hl
and a
ret
.load_word
ld a, [hli]
ld b, a
ld a, [hli]
ld c, a
ld a, [hli]
ld d, a
ld a, [hli]
ld e, a
ret
.store_word
ld a, b
ld [hli], a
ld a, c
ld [hli], a
ld a, d
ld [hli], a
ld a, e
ld [hli], a
ret
.and_word
ld a, [hli]
and b
ld b, a
ld a, [hli]
and c
ld c, a
ld a, [hli]
and d
ld d, a
ld a, [hli]
and e
ld e, a
ret
.or_word
ld a, [hli]
or b
ld b, a
ld a, [hli]
or c
ld c, a
ld a, [hli]
or d
ld d, a
ld a, [hli]
or e
ld e, a
ret
.rotate_word_left
sla e
rl d
rl c
rl b
ret nc
inc e
ret
.rotate_word_right
srl b
rr c
rr d
rr e
ret nc
set 7, b
ret
.combine_states_and_constant
; must preserve a, hl
push af
push hl
ld c, a
offset hl, $44
ld a, c
call .initial_states_combination
pop hl
push hl
offset hl, $50
call .add_word
pop hl
push hl
offset hl, $40
add sp, -4
push hl
ld hl, sp + 2
call .store_word
pop hl
call .load_word
ld l, 5
.rotation_loop
call .rotate_word_left
dec l
jr nz, .rotation_loop
ld hl, sp + 0
call .add_word
add sp, 4
pop hl
pop af
push af
push hl
call .add_iteration_constant
pop hl
pop af
ret
.initial_states_combination
cp 20
jr c, .selection_function
cp 40
jr c, .xor_function
cp 60
jr c, .majority_function
.xor_function
call .load_word
call .xor_word
.xor_word
ld a, [hli]
xor b
ld b, a
ld a, [hli]
xor c
ld c, a
ld a, [hli]
xor d
ld d, a
ld a, [hli]
xor e
ld e, a
ret
.majority_function
add sp, -4
call .load_word
push hl
push de
push bc
call .and_word
push hl
ld hl, sp + 8
call .store_word
pop hl
pop bc
pop de
call .and_word
ld hl, sp + 2
call .or_word
ld hl, sp + 2 ;faster than push/pop, and same size
call .store_word
pop hl
call .load_word
call .and_word
ld hl, sp + 0
call .or_word
add sp, 4
ret
.selection_function
add sp, -4
call .load_word
push de
push bc
call .and_word
push hl
ld hl, sp + 6
call .store_word
pop hl
pop bc
ld a, b
cpl
ld b, a
ld a, c
cpl
ld c, a
pop de
ld a, d
cpl
ld d, a
ld a, e
cpl
ld e, a
call .and_word
ld hl, sp + 0
call .or_word
add sp, 4
ret
.add_iteration_constant
ld l, -1
.iteration_constant_loop
inc l
sub 20
jr nc, .iteration_constant_loop
ld a, l
add a, a
add a, a
ld hl, .iteration_constants
offset hl
.add_word
inc hl
inc hl
inc hl
ld a, [hld]
add a, e
ld e, a
ld a, [hld]
adc d
ld d, a
ld a, [hld]
adc c
ld c, a
ld a, [hl]
adc b
ld b, a
ret
.update_buffer_word
; must preserve a, hl
push af
push hl
sub 3
and $f
add a, a
add a, a
offset hl
call .load_word
pop hl
pop af
push af
sub 8
call .xor_word_by_offset
pop af
push af
sub 14
call .xor_word_by_offset
pop af
push af
push hl
and $f
add a, a
add a, a
offset hl
push hl
call .xor_word
call .rotate_word_left
pop hl
call .store_word
pop hl
pop af
ret
.xor_word_by_offset
push hl
and $f
add a, a
add a, a
offset hl
call .xor_word
pop hl
ret
.update_states
; must preserve hl
push bc
push de
ld a, $4c
call .shift_word_position
ld a, $48
call .shift_word_position
push hl
offset hl, $44
call .load_word
call .rotate_word_right
call .rotate_word_right
call .store_word
pop hl
ld a, $40
call .shift_word_position
pop de
pop bc
push hl
offset hl, $40
call .store_word
pop hl
ret
.shift_word_position
push hl
offset hl
call .load_word
call .store_word
pop hl
ret
.initialization_data
db $67, $45, $23, $01
db $ef, $cd, $ab, $89
db $98, $ba, $dc, $fe
db $10, $32, $54, $76
db $c3, $d2, $e1, $f0
.iteration_constants
db $5a, $82, $79, $99
db $6e, $d9, $eb, $a1
db $8f, $1b, $bc, $dc
db $ca, $62, $c1, $d6
Comments