# @file fors_pkFromSig
# @version 1.1.0 (2025-12-31T07:59Z)
# @author David Ireland <https://di-mgt.com.au/contact>
# @copyright 2023-26 DI Management Services Pty Ltd
# @license Apache-2.0
"""Compute the public key from the signature."""
from slh_adrs import Adrs
from slh_util import hash_root, authpath, fors_sk_gen
from slh_sha256 import H, F, T_len
# DEBUGGING
DEBUG = False
DPRINT = print if DEBUG else lambda *a, **k: None
PKseed = 'FA495FB834DEFEA7CC96A81309479135'
n = 16
a = 6
t = 2**a
k = 33
tree_address = 0x7cdcef4b8fdb03b0
leaf_address = 0
# indicies = base_2^b(md, a, k)
indices = [50, 47, 49, 35, 39, 21, 57, 21, 2, 0, 31, 56, 18, 58, 58, 31, 31, 43, 35, 26, 8, 7, 31, 13, 21, 57, 63, 20, 33, 5, 8, 32, 28]
SIG_FORS = """
925BB207D49E62BCB9B1C4685154A8B3
2E58B70C7AED0E28507F31B49EC7ED6E
D6DCB8DB2DA90FE938994D75C80E6712
F2421C22DEF8AF88906B768333E7EBF6
DDF7B84DC01F06731DD640CF93F57927
BB56F9DA9D4B2ABE60C81D863A20F8E5
C5CCE74326D6181D01B74E3CD7F794A9
8B4ED7A791A1B77C561A6E7AE64E4E17
481DE4CE7E26065D90AE21C965FEBA33
02102D7564E3B7414E1AA62271E9B4DF
B42C57C44726AF6FE7F3BDD486D7D578
B4B4BA8EBC1F5D7243F94D2D2D4CB55B
7F95C3020E05A6CCBE12CBDFFD6466B5
B34369FA56839A0E05AF5C6613E4A229
895CF5A834880A2C3937CC759F367356
7F39FF2B8A0613EEE33963B06D200181
F3FE69B507F2172E459B989A8819C7EB
BA3AAF31F9D589DC0123012B787B60DC
E3DA8A76D1A3476EF08FB8ACB72F6C1F
7C8B6929642822EAA13965D6C1F3C58B
600CF029758C41E26E0EDB6FD5F2EB13
EB91D95ED3AB976E5C6DFE1C80879B8B
E68DBFB9F8E2E60D822D88DCAD48EF2E
F89F5486FCE1506002E7A7AD8F0E5837
4E3F82B6E72CF0CD04B86BBB9F261BEA
70C785521BA607B8A2DE642C6EB84F69
1307618C60AD713F7B10857D28613A64
18DD1297544671091668F5E8EF5ED296
DF37CC6E45B36F261A66B4AD8BF55C63
298A6FD79B9A128D44DF4818E613B783
DD8D8116DFAB297F520163A15F35A4B9
6105D7A695C723F11E38964C05F5840A
D333FBCF1862B2BFD0433D645F411E73
C6434480E7C55EBD1B4E1B786A7A333B
8FFC5E77CB303A3D093FA0D18DD223FD
3CC352EDD11F95200A2D6791011B40EF
6CCEAC57842961CDF74DCC5CE09B219A
615B08A9BB92E2F001B7E5FD87D092BE
800DFFA75D1D10AD80E543A7809384C8
C857780D66B9A7A9A7B15F72C1AEC5EE
6F8CAF7D6B128DFD34E26AC6F5267052
557E2AF504BB5E8110F28B8CB3268900
D37E5E53A2642FF7AD1EC4B690A99BD6
2A3883537E3D77F80B09D27DB2A28DA6
59A3B100E3B65088E837826FA707E8E3
9149056C3BB13D957486964351D88CE1
BCB69968C85690C959992AF98609AF5E
D34A681FD32F8D1A5E219D38D4CC2281
82697C9389B2E9B5059B8AC4A280DFE3
D6838D879830643CFF92CA02A1C9EB16
43516A31C55E0E8D0F9CBF16D01FC0B8
CA214259DED8CAEA43A013A645F9CE53
00520066CD2AC04BAF8D49AE7694D40B
B60AAD324569690218FE19DFA58EF73D
62A831501AA25F7EFB5FC9C8150955FE
6524DE636CE526B100A29E6E48EE047F
33BA6C0BA5ABD5E5720945796A57FC38
9CAA1755A339F6C584B13D6971833C9E
865398C8BF486A5F99EDC9E5D69A04BA
1118A3A9140CD52A951D283242B55832
82DD5CA1AFC867C14947F68F8D3D9110
5AC4AA565650430BA9334FA8A8C5B76B
AB24D1BE6BBAC8A478B89EF8E9E8B33B
F38CFDFFA1D07F984036BB5D9A71031A
67050BF451468D1622AD99EBFD71B7AD
F09D1C5599C347A8778776E7D9DF5495
728FA6E8C6A18FFD7DD6CF2CA7BBCC84
B12EE03D9AC24F2EE35F4925161D41F6
1EC3D51D9A96A1CD67C84E7350DE302C
CBBE3BD56EB1B1682FD60DC5EFC1AF97
A9A8AF08F088E9B561221111CF29E63A
3E7715C84BB0B9756FD8D8A92CAA2EF6
58E268DE024A54B9B6EBDC681AB04415
F5656315B35055160DB4083D184893E8
D4C870B803394BAB5E38F5C390FAFECD
22B052EE4461A624587F6EBE70B90A84
0540F009715B0AAE502D2811BB7E345F
F2F4F779AE981287BFB96B9A73B999D7
778FC47718D47907F60B273C37DD1E7A
DF6FAE38F6BC5F392927F18E742CFCBE
81C0A4C8C75403361F1BA7F867DD94F4
D22AD03C38D554BD9E4DE497ED63C156
BA9086F4C8B4D087529EDCC0295A93AF
B5373BF46BD04B2E5EA5863C850C3283
B3E7524BD5E2ED5937742062EC144E82
9BFFCB9DAB3F9C4C5DDFE8AFE51BB58B
A2D0C8C32393AE9F49764ECF7BBBEE80
7B98EF8FA9B18A88731B5388C717F321
BD4761A74606226C5C9E3E203BF47B17
24DA6AA13FF7267B99CE68523050523F
C4B8A42FDFAD0F4A0EC0340BB6C1A58B
4DB63C03589632485496407B90169AE9
F7C7B287E0841B6CE570942FA518CCD8
0A355F64FD5F739BCC31BAD3C618B591
F0CDE79614388B538EFCCE119B0884A8
50FBA18BA41F39F08E84D8E6B38D7760
A39DCCCAF4A031EAE014C6D6188FE033
3D166719D275BB56056EA4B8203673F0
8BB5C44C57B209AB57C17475E22E55B0
6453998F919557582959376745FA1E34
8E9DA508CF2E96FB4FEB4B903B363852
51B34F319D9ABE258E0B8318A7C9D456
47F99CD4A317A9CF017ED9B341C1FD50
1426BB6C04E12CFB5220AE2A1DFC02DF
A2BE4AC859F837EAA1FF14D99D86A26F
BE346F869BA7B662EE5B69FD1B8D16FE
352BC5720F402A009C649DAE7DDF6CEF
84DD2251D5F97C91ACEA5326DBFDF4CE
695B5C5908B43EAA79EC1670D7566599
1AEF8979747976173A5875C912FFF4EE
76EB2FFAC233B77FD330B6F888CF0393
FA381328BD9936A977DE7240772876BF
15A3009ADFD2AB9870B49E79201AB912
D57FC237F1D83B63D8EB1EF7EC1055B6
A4D2755BCE09D9F2BED40D36033360CB
9375A3A5EF8BA045A816914D3489DF7B
6B2A2FDB5FADC6B3E1A9CF4063D06B43
D7ED75A8C78674CE7858FEC0ECAB11E1
A041FF986A904BD84968F299419DF5F9
60C2736E75718008F9DFCECDF20EA3C9
A79190AB27033989A40D3B97D89FF662
E63CC0B639E77FD3E983239D8E59F058
5B12C803E1BD3A5865D1D4D3F022ADB4
DEEE488F2D2C08F1997D8601D702CD9E
27984E171A6364C6887E8A625A23EF49
88FBC6888A2A49C17CB596E4C415BF2C
E9EA4741BD00E65AE90B8C53866CA49F
20E575A31F011D22ED8DE7A41F71BD9B
B9F7CE42E0A5705C3498415C0CE46255
8366B00DADD9DA6F17C666D46695B250
E651965E814EC70D78C507E4EDB96567
8C1F80CDA6C7CFD720FC133582F03F84
8849B261892696765F327DBF653CC7C8
8FA9ECE9CC172B2E91FFE90CAACC876B
C26E44B2A4FEF46A4E2BAD72A55D268E
4E99B95D13A196FE6ABF7DEECE54C767
7813EB04AF9601B323FD27D90D8701EB
F06E539796E68D320BDD2A8638029C66
12C519CC44D1AA2BABE31DDAB3A83714
C805B98731329CD1FADA30E7E690B949
E2E7417975BD83D8130DE44D186A90D0
F435C78FC4EB6A02ED891FD1C67BB405
2A6339CD75AD525D8F84B4CEB33900F7
D1214C44B1EB05C224CC9569FD58CA77
EA9193E591E658058E50555C63D98F85
28467F134468426304D9771346AEDD3D
072059103000906D1843B19B23490070
DD6A9F5C6185C34ED9CB73CBFF159966
2727CE40795CBB8FC3BB669F670FEC73
1A226AE12B08FA4F6C23B3C3B2366490
CC023C4BE2766168E776F1C186DDE099
DAAC158D2CC085577271F7965545F2FF
9EB02C670E5CF5625722A140E9629124
6E941E0B9D0F94C05E66C9EAC61A1E6D
5265B9491D6E0FE13C3DAF44BD6AE2C3
868E262767AD21106831FC99101E3A8F
47127FCBE648A6CFDF841686B2770645
6E9BDAAE54E5689EC2FB6274749C955A
C62892B62AF27ECA451EA199D565891C
8C11E36F24B13A74A46D5194272FEB46
89F598D2BE372BCA45E177B80D7C352A
B598AC0EE6F72C9531074F98860AF8E7
D0F49258F50414525715262D689B1316
4EEC4B8A0419B5E6E1C831249375F6BA
B546102CA90333B15A24E543A2579B07
4EF40E9237150561405804FCA0095D5C
4D8D6456DF31DD847F517C8FBEEA4CA8
EA88CCE339A4C7A565C43674BD55C585
21E4E50E837A76C34CC1F625AEA9D4AE
909BADA0C37B5E47CB26562BE2E37402
D2210A82CA8E397CB2B88453A2F0FE77
9E7C6A74FA32B80A99352790B6D87147
0BA75506F8E6CF0D7F9DF4716D86FBA4
0D2F2FB7C3C6ECCE2B534B4F693BD5A6
DD7E1DA3A1B1209A17FEB7E9830E67BE
C26F277921D048F32B9ABED990AB2A7A
DA21374D1BD64D3EBC5333F437492D12
D5E89798AA7B83E6467BF69E221705CB
06CE8B2C96AE7F8D0B41AF3DB1F183AB
C5151C02C3CFED01F58266E3C2E67A23
2DD2D11F8573B670A974CE7D9C8F6FAB
7D70C7437A0A0EA38F094A0908F5162E
3C63C6FE09701D4AB6EBEDDDF8CB52D8
EFF8C174A051A841FC36DF127501B2DA
18F087B98B0F80DEE70CB76700662192
89E9CA9C1A9EFFDBE14DE19D20850D98
149CFF50314B91891097FAA023D69900
9BCE636E401610E24667AC3D5B41ADAD
D82872FB0874BC42593134086538DB3C
BCA27BF7B8CED845B9FB7A005E813E38
971F36BB793E96CBF65CE3E4BB2B20FA
E2DFBF63B84962B7D7960BDCAEEC39FF
E5587586C5A4E080C4E3C9A370BA4822
637524925A4AD8565771E1EF56664177
3410C6EDBECFEA9382E9B19EAEB05DF8
851220DC24B4211D5AD427B8B4824ADE
2BF31983B2B426D7E872C205A0132C6D
413B53CF4B975CE36749A75994589C34
ACC9A87B8B147DC886CC30E02355C845
79C64C1D9A466A44BDB6BABED60D143C
D89FC9AAAB0B400154E4FB1AE0915A72
0C8B5BB56875EE54F44ACB9BDB8D447D
64A407956FCE1C700CB86F014F398A34
466C4F8F8D9DB8B8EEB16762A02B314A
05799E7DCE5C1738EAFC729BF655E351
E3CD6F061CA4CF25E98FFB486B6DCCAD
82FAE13896B7DFF055C58B2B7643D402
57EC1FA091C654FBE16338A02276AF20
EAB9A21993DDECDBFF5C7F00EE9FC7EE
9E5AA5C50C43F657C7E65B4D865B1822
EA0CFA3010F310CA66174EB341C82E22
D797A252C6A8DE77452E8CC6117673B1
0041E8165ACA650B5A6DBCBE29601BC5
70C13C7D8DD57679ED3F9D459F4BF0A2
9BDD476FAC13CC4CFCD9A3C65B63F57A
93DB350BDABCF697F069DD909B480817
6E265BB268FB9BC4200B83BC7B18D43D
AC8997BF4834A14C4107F3C9E597F77A
D3313E670159D94ADBC46DA1F2B69642
B7FA8E1EBFFC228A222F951BE0ADF614
22878E4939EA32B83242692A140D80DF
11D95734E69B952FF7C6716E0B360BE4
D0BC3D675E0CFB721681911BBF5AD804
0A24901159B1D805CE023E731CCDE39E
2B38F096578C9A974AC0CE9A28D92351
5C1FD369CDA5F3FA35E7358EFDB91A07
71F3DAA64E685F5E24BC819C93486B28
71FE59A0A2749A15BCFE36C4AB4AC2ED
4803015FAF8BD4C309EE883D4F58131F
778FBB608F07C3FB62E588CC47902B6A
0C646676640AB0EE1B342537E9376CE5
""".replace("\n", "")
def getSK(i, sig):
sigarr = bytes.fromhex(SIG_FORS)
sk = sigarr[i * (a + 1) * n : (i * (a + 1) + 1) * n]
return sk.hex()
def getAUTH(i, sig):
sigarr = bytes.fromhex(SIG_FORS)
# FIPS.205 Algorithm 17 line 7
auth = sigarr[(i * (a + 1) + 1) * n : (i + 1) * ( a + 1) * n]
# Split into array of `a` elements encoded in hex
authhexarr = [auth[j * n:(j + 1) * n].hex() for j in range(a)]
return authhexarr
def is_even(num):
return num & 1 == 0
#print(SIG_FORS)
root = [''] * k
node = [''] * k
adrs = Adrs(Adrs.FORS_TREE, layer=0)
adrs.setTreeAddress(tree_address)
adrs.setKeyPairAddress(leaf_address)
for i in range(k): # range(k)
sk = getSK(i, SIG_FORS)
print(f"sk[{i}]={sk}")
adrs.setTreeHeight(0) # Compute leaf
adrs.setTreeIndex(i * t + indices[i])
node[0] = F(PKseed, adrs.toHex(True), sk)
print("node[0]=", node[0])
auth = getAUTH(i, SIG_FORS)
print(f"AUTH[{i}]: {auth}")
for j in range(a):
adrs.setTreeHeight(j + 1)
if is_even(indices[i] // 2**j):
adrs.setTreeIndex(adrs.getTreeIndex()//2)
DPRINT(f"j={j} even {adrs.toHexSP(True)}")
DPRINT(F"{node[0]}, {auth[j]}")
node[1] = H(PKseed, adrs.toHex(True), node[0], auth[j])
else:
adrs.setTreeIndex((adrs.getTreeIndex() - 1)//2)
DPRINT(f"j={j} odd {adrs.toHexSP(True)}")
DPRINT(F"{auth[j]}, {node[0]}")
node[1] = H(PKseed, adrs.toHex(True), auth[j], node[0])
node[0] = node[1]
print(f"node[0]={node[0]}")
root[i] = node[0]
print("ROOT:", root)
forspkAdrs = adrs.copy()
forspkAdrs.setType(Adrs.FORS_ROOTS)
forspkAdrs.setKeyPairAddress(adrs.getKeyPairAddress())
print(forspkAdrs.toHexSP())
pk = T_len(PKseed, forspkAdrs.toHex(True), "".join(root))
print("PK =", pk)
assert(pk == "33af163817cd6c2bea881ddf7d2b89ab")