1 module dcrypt.pqc.sphincs.horst; 2 3 import dcrypt.pqc.sphincs.common: hash_2n_n_mask, is_hash_n_n, is_hash_2n_n, is_prg; 4 import dcrypt.pqc.sphincs.treeutil: TreeUtil; 5 6 private enum seed_bytes = 32; /// Size of seed in bytes. 7 8 /// HORST few-time signature scheme as described in 9 /// https://cryptojedi.org/papers/sphincs-20150202.pdf 10 /// 11 /// Params: 12 /// n = Bitlength of the hash values. 13 /// m = Bitlength of the message hash. 14 /// hash_n_n = A hash function mapping n-bit strings to n-bit strings. 15 /// hash_2n_n = A hash function mapping two n-bit strings to n-bit strings. 16 /// tree_height = Height of the HORST tree. This is called `tau` in the paper and `log_t` in the reference implementation. 17 /// prg = A pseudo random generator function. 18 package template HORST (uint n, uint m, alias hash_n_n, alias hash_2n_n, uint tree_height, alias prg) 19 if( 20 is_hash_n_n!hash_n_n 21 && is_hash_2n_n!hash_2n_n 22 && is_prg!(prg, seed_bytes) 23 && n % 8 == 0 && m % 8 == 0) 24 { 25 26 enum hash_bytes = n/8; /// Size of hash values in bytes. 27 enum msg_hash_bytes = m/8; /// Size of message hash in bytes. 28 29 enum log_t = tree_height; /// Height of the HORST tree. 30 enum sig_bytes = (k*(1+auth_path_len)+(1<<x))*hash_bytes; /// Size of signature in bytes. 31 32 private { 33 alias ubyte[hash_bytes] H; /// Type of the hash values. 34 alias ubyte[2*hash_bytes] M; /// Type of bitmasks. 35 36 alias TreeUtil!(hash_2n_n, H, M) Tree; /// Provides some hash tree algorithms. 37 alias hash_2n_n_mask!(hash_2n_n, H, M) hash_nodes; /// This is the function used to hash two nodes. 38 39 enum t = 1 << tree_height; /// Number of tree leaves, 40 enum k = m/tree_height; /// Number of revealed secret-key elements per HORST signature. 41 enum x = best_x(tree_height, k); 42 43 44 /// Finds x that minimizes k*(tau-x+1) + 2^x and thus leads to mimimal signature size. 45 /// If the minimum is on two successive values then take the larger x. 46 uint best_x(in uint tau, in uint k) pure { 47 48 uint f(uint x) { 49 return k*(tau-x+1) + (1<<x); 50 } 51 52 uint x = 0; 53 54 while(f(x) >= f(x+1)) { 55 ++x; 56 } 57 58 assert(x <= tau); 59 60 return x; 61 } 62 63 private unittest { 64 assert(best_x(16, 32) == 6, "best_x() fails for sphincs256 configuration."); 65 } 66 67 68 enum level_10_size = (1<<x)*hash_bytes; /// Byte length of hashes on level tree_height-x. 69 70 enum auth_path_len = tree_height-x; /// Number of elements in authentication path. 71 72 /// Return type of horst_verify. 73 @safe 74 private struct verify_t { 75 76 @safe @nogc nothrow pure: 77 78 @disable this(); 79 80 this(in ref H root) { 81 this._success = true; 82 this._root_hash = root; 83 } 84 85 this(bool success) { 86 assert(success == false, "A root hash must be given if successful."); 87 this._success = false; 88 } 89 90 private bool _success = false; /// This is set to true if signature verification has not failed. 91 private H _root_hash; 92 93 /// Returns the root hash of the signature if the verification has not failed. 94 /// Check `success` property first. If `success` is false then `root_hash` will fail. 95 /// 96 /// Returns: The root hash of the signature. For a valid signature this is equal to the public key. 97 @property 98 public H root_hash() const { 99 if(!success) { 100 assert(false, "There is no root hash because the signature is invalid anyway."); 101 } 102 return _root_hash; 103 } 104 105 @property 106 public bool success() const { 107 return _success; 108 } 109 110 } 111 } 112 113 @safe @nogc pure nothrow 114 public ubyte[sig_bytes] sign( 115 out H public_key, 116 in ubyte[msg_hash_bytes] msg_hash, 117 in ubyte[seed_bytes] seed, 118 in M[] bitmasks 119 ) 120 in { 121 assert(bitmasks.length == tree_height, "HORST requires HORST.tree_height bitmasks."); 122 } body { 123 H[t] nodes = gen_secret_key(seed); 124 ubyte[sig_bytes] sig; 125 // Split message in k parts. 126 ushort[k] idx = msg_to_indices(msg_hash); 127 128 /// Interpretation of sig as k*(auth_path_len+1) hash_t types. 129 H[auth_path_len+1][] sigma = 130 cast(H[auth_path_len+1][]) sig[level_10_size..level_10_size+k*hash_bytes*(auth_path_len+1)]; /// k pairs of (sk_{M_i}, Auth_{M_i}) 131 assert(sigma.length == k); 132 133 // Reveal secret key elements. 134 foreach(i; 0..k) { 135 sigma[i][0] = nodes[idx[i]]; 136 } 137 138 // Generate public key elements 139 // and overwrite all secret elements. 140 foreach(i;0..t) { 141 nodes[i] = hash_n_n(nodes[i]); 142 } 143 144 // Calculate hash tree level by level and store the authentication paths. 145 // TODO: use treeutils 146 size_t level_size = t; 147 foreach(l; 0..tree_height-x) { 148 149 // Store siblings in auth. path. 150 foreach(i; 0..k) { 151 size_t sibling_idx = idx[i]^1; 152 sigma[i][l+1] = nodes[sibling_idx]; 153 } 154 155 // Move the index to the parent nodes. 156 idx[] /= 2; 157 158 // Generate hashes of next level 159 foreach(i; 0..level_size/2) { 160 nodes[i] = hash_nodes(nodes[2*i], nodes[2*i+1], bitmasks[l]); 161 } 162 level_size = level_size/2; 163 } 164 // leaves[0..1<<x] now contains the hashes on level x. 165 assert(level_size == 1<<x, "Size of level x must be 2^x."); 166 167 // Copy everything into one octet string. 168 const ubyte[] linear_sigma_k = cast(ubyte[]) nodes[0..1<<x]; 169 assert(sigma.length*(auth_path_len+1)*hash_bytes + linear_sigma_k.length == sig.length); 170 sig[0..linear_sigma_k.length] = linear_sigma_k; // Append hashes on level (tree_height-x). 171 172 // Calculate root hash of the tree. 173 public_key = Tree.hash_tree!(1<<x)(nodes[0..1<<x], bitmasks[$-x..$]); 174 175 return sig; 176 } 177 178 @safe @nogc pure nothrow 179 public verify_t verify( 180 in ref ubyte[msg_hash_bytes] msg_hash, 181 in ubyte[] sig, 182 in M[] bitmasks 183 ) 184 in { 185 assert(sig.length == sig_bytes, "Length of `sig` must be exactly `HORST.sig_bytes`."); 186 assert(bitmasks.length == tree_height, "HORST requires Horst.tree_height bitmasks."); 187 } body { 188 const H[] sigma_k = cast(const H[]) sig[0..level_10_size]; // Extract hashes of nodes on level tree_height-x. 189 assert(sigma_k.length == 1<<x); 190 191 assert(level_10_size+k*hash_bytes*(auth_path_len+1) == sig_bytes); 192 const H[auth_path_len+1][] sigma = 193 cast(const H[auth_path_len+1][]) sig[level_10_size..$]; /// k pairs of (sk_{M_i}, Auth_{M_i}) 194 assert(sigma.length == k); 195 196 // Split message in k parts. 197 ushort[k] idx = msg_to_indices(msg_hash); 198 199 H[k] n; /// Hashes on level tree_height-x. 200 201 /// Get hashes from leaves and auth paths. 202 foreach(i;0..k) { 203 H Li = hash_n_n(sigma[i][0]); 204 n[i] = Tree.validate_authpath(Li, idx[i], sigma[i][1..$], bitmasks); 205 } 206 207 /// Compare the hashes to sigma_k. 208 foreach(i;0..k) { 209 auto index = idx[i]>>(tree_height-x); /// Index of hashes in sigma_k. 210 211 if(n[i] != sigma_k[index]) { 212 // fail: signature is not valid ! 213 return verify_t(false); 214 } 215 } 216 217 // On success: calculate public key root hash. 218 H root = Tree.hash_tree!(1<<x)(sigma_k, bitmasks[$-x..$]); 219 220 return verify_t(root); 221 } 222 223 224 @safe @nogc 225 private H[t] gen_secret_key(in ref ubyte[seed_bytes] seed) pure nothrow { 226 H[t] sk; 227 prg(cast(ubyte[]) sk, seed); 228 return sk; 229 } 230 231 private H gen_public_key(in ref H[t] secret_key, in ubyte[2*hash_bytes][] bitmasks) pure nothrow 232 in { 233 assert(bitmasks.length == tree_height, "bitmasks must contain `tree_height` masks."); 234 } body { 235 H[t] pk; 236 foreach(i;0..t) { 237 pk[i] = hash_n_n(secret_key[i]); 238 } 239 return Tree.hash_tree!(1<<tree_height)(pk, bitmasks); 240 } 241 242 private H gen_public_key(in ref ubyte[seed_bytes] seed, in ubyte[2*hash_bytes][] bitmasks) pure nothrow 243 in { 244 assert(bitmasks.length == tree_height, "bitmasks must contain `tree_height` masks."); 245 } body { 246 auto secret_key = gen_secret_key(seed); 247 return gen_public_key(secret_key, bitmasks); 248 } 249 250 /// Split message in k 16-bit parts. 251 @safe @nogc 252 private ushort[k] msg_to_indices(in ref ubyte[msg_hash_bytes] msg_hash) pure nothrow { 253 static assert(msg_hash_bytes == 2*k, "msg_to_indices() is not designed to work with this parameters."); 254 ushort[k] idx; 255 foreach(i; 0..idx.length) { 256 idx[i] = msg_hash[2*i] | (msg_hash[2*i+1]<<8); 257 } 258 return idx; 259 } 260 } 261 262 // sign() sanity test. 263 private unittest { 264 import dcrypt.pqc.sphincs.sphincs256; 265 alias HORST!(256, 512, hash_n_n, hash_2n_n, 16, prg) Horst; 266 import dcrypt.random.drng: DRNG = HashDRNG_SHA256; 267 268 DRNG drng; 269 270 ubyte[seed_bytes] seed = 0; 271 ubyte[hash_bytes*2][Horst.log_t] masks = 0; 272 foreach(i;0..Horst.log_t) { 273 masks[i][] = cast(ubyte) (i+1); 274 } 275 276 immutable auto public_key = Horst.gen_public_key(seed, masks); 277 278 ubyte[msg_hash_bytes] msg; 279 drng.nextBytes(msg); 280 msg[0] = 0x00; // 'extreme' cases 281 msg[1] = 0xFF; 282 283 hash256 sign_pk; 284 auto sig = Horst.sign(sign_pk, msg, seed, masks); 285 assert(sign_pk == public_key, "HORST.sign generates wrong public key."); 286 287 auto result = Horst.verify(msg, sig, masks); 288 289 assert(result.success); 290 assert(result.root_hash == public_key, "HORST failed."); 291 292 // modify the message 293 auto invalid_msg = msg; 294 invalid_msg[0] ^= 1; 295 result = Horst.verify(invalid_msg, sig, masks); 296 assert(!result.success); 297 298 // Sign with different key pair to get a valid signature but no matching public key. 299 seed[0] ^= 1; 300 sig = Horst.sign(sign_pk, msg, seed, masks); 301 result = Horst.verify(msg, sig, masks); 302 assert(result.success); 303 assert(result.root_hash == sign_pk); 304 assert(result.root_hash != public_key, "HORST failed."); 305 306 } 307 308 /// Test against reference implementation. 309 unittest { 310 import dcrypt.pqc.sphincs.sphincs256; 311 alias HORST!(256, 512, hash_n_n, hash_2n_n, 16, prg) Horst; 312 313 ubyte[seed_bytes] seed = cast(const ubyte[]) x"bdd61f23a3c7e1c1135c4aed4c2c71d4a93b0253fd01be2aeb2a0fdbd81122bf"; 314 ubyte[hash_bytes*2][Horst.log_t] masks = 0; 315 316 foreach(i;0..Horst.log_t) { 317 masks[i][] = cast(ubyte) (i+1); 318 } 319 320 ubyte[msg_hash_bytes] msg = cast(const ubyte[]) x"18c7860966787180346ffd95bb54cd3c57961c995aeb76808874fa315a9ca8e45e0425fbe7cfdf8a7631bf549d479dd4f8c433f57399a04752a89b191cec6b50"; 321 //foreach(i, ref m; msg) {m = cast(ubyte) (4*i-1);} 322 323 hash256 sign_pk; 324 ubyte[Horst.sig_bytes] sig = Horst.sign(sign_pk, msg, seed, masks); 325 326 string expected_sig = x" 327 dfe67673177c6a49c8ff9e941ebefcca91975eb73dfe86f02ff5d75959aed314 328 ddc33cf74025e41575490669bf1c146cbbd0b5248c9585fde932c5f0313df601 329 072f47aa57e4853be5319fe36d6a737b708484d82881435f50ab8ca19884917b 330 c2afae587e36a45dfc8410f14f45be349b353a8ff0865b35964a47c2ea193722 331 b4cc45f62a4825ecac038f946da79268cab5fad559d7f36a201a024e264d8efb 332 de380dea3922d0582f734c43ef8ed5bdbf16f7bd490394f078e5374511d2f2b7 333 8daba89714eefb8957055c2d6b00c428647e4cf82423966297edf6fe7cc4b91a 334 f7fa854d06d614c53c06ab1db74d7d16bd995334c02e49dcea24244ca750807a 335 a73055b93dd0225047acfa48b97c3b9ba1f0db2177bd076b5776b49a69bd5f07 336 202c32a8ba49459fa58f793b40b036c8f6fbd534a1526a7a3bc6449b5b1e2dfc 337 2761b9662a44ab5decf5bb5dbd0a658681fbeefb143e8a7f075dfc2bcfe2f1bb 338 a658589c83da03be7e03cb2651ba0037830ef3a1b715c564282aa1fca3fea8aa 339 822232c0d3573d311160914ce68104cdebe097d2113353f4ec79f182b4d3e628 340 7d525e3f20e8423ca769511ab1535967d4a55b3f621ee8e65de878f205fe4095 341 039444e4e079a71d6982f6dbf85706f99231dc6569aede8b6b1aaa909dad1fc3 342 5f05164f514e90adba52f7f044ec89d48a7340fd0c5d636337e4928e82990f8e 343 675b83729f92d86a167705449036c6414c16440cb7fbb2ed7ebf2b8a0798f47c 344 ed1d477bd1ebaee3361cdcaaa1e51e502cf0bf2fbe4ae409acc7b2e1a5a2fe0b 345 02b7bf39aa8212841e77452a1accdc5fbae3ea500777046c6d5d35a477095bdc 346 16e52f86251e4efa72082573b88283d149b0efaef4a91af5253160266c25d55e 347 e8d48b4e45f9f3c0fcffdb0f5c2b39cc80220b86fa3210504644137fd0a19a0f 348 ac23708fbca02ff0642ab40ffd56e2ffb9050c02087289cb76a8a36233ff843a 349 860b11f3dd11126564b07874cb59b64960adefab4f80c3a03ac77ec30f7a8e09 350 15fe8a517318bbdefb1130db1d5e07f6b4afb57350bc2e97d8e8d784eb7922e2 351 1b66c698bb3930273a3fbe1709c8df2e093831ac3c1671c1abb8cbf00bdbf63f 352 5202a3439f3af0ee1d519834c7cc5f4de7e6be2fff64f185feec11f62479f3fa 353 0daa93cac27869a205f1a7105b94b1a23ae3247723786216b51150bb5038648a 354 c847ceba75a3269021aa5917cc4ce28ab9376a8e60380fef1ab173e3fa9e6943 355 43a5aff6e6754705a699a6520dfcc5dfe85fbb63a200bdf923e4c824f445c1f1 356 e4cf8265084ef86848fde71ccba2e641d1ed6868aa57899b493d56179bfed463 357 8f78ec0a7d3236620754eb5e877ed3a407c8ca389600afe51ee50dc01316329d 358 7ef7d0a772ca9188bbce2a94f89c489ec9405b7cf62137336c436f732a1565b4 359 380f5b708f6e549f3708535c6e1710b64f43a2a6359d7812de21f5ca16056968 360 88c205a053c92c70c0a45b02aed6454545a52a0559a3eea827eb2f7fb31482fb 361 a7d5d9027469ed0c3888ed2b1a18ff937b1bf0a83808ea5d65ea77ec01e248a6 362 ae6985a0c0e4e0fd101143915433b2666479454ffbbe928ec780abb582b53de4 363 9aa87f49eedb5161d48be48a099cf74bf9d5d17a42c42ea43279f55457531c7a 364 a17574b2f1d6ac39aa29c0732364de896f818362ce5b2497440bc1ecf5c52f43 365 0cd3a2e45180dcf71953045193701deefb3906fdfc32f5fbfbc1b8b79d66ded7 366 d38d4d675542452da6c681b5871493af61b2c18aa7a59236be30cc3a496abc23 367 b06aec01079727b6fb3323bb28d5b20fbb1e6a1af5ebb31bd3eb84b7ba19bcb3 368 94f239b3254d3c62998661671a7e86702d0739f295b7f371e5c8ba0c6af80fa1 369 ed49494b1877325091a478eabbfd0f9ab0ad9289f93fcd8d8ff31c2560411d94 370 156ae104638e7b9e122f3914e6278dc196ff4d7246da3efc72af722d8dccb409 371 514f7383c6eda8d30ae2cf75f592e7f3e3ab405258658c853f1d8e24f456b9ab 372 da90d5d442a050b91ada84581c357126b2435a39167aa3c1ecf1bd03f1808eb5 373 45f2e8e34c0da329c7f853d2e59b6c42ce098fb9ce2d6bbc65c052a24bcdbc47 374 9f22ab91f80c54f9d4592c379259ae25d8f13295b89fc8dc58d482ece11c4670 375 a609e33cadc74946a7db8bf88b1a193fac9b6321ba1bf0874775fb176fe0e5e4 376 aebab20d0a224202f58392dec05779f445fefe65e53f336da3d1af533d452424 377 6b1bf0f52873129003e92e87f46878236518286294c15caf042ca56b71df67bd 378 5c68e6f51c8b4806f9f5d7d94a8938e80c7d3b3b71c4a05bf02b6221397668f6 379 2f555a5d889b5c1f72c691b5d9e6824bdff1c0c8c224154d4509f64771cdf561 380 3cb4b132f57c431c4ed3277e59c9bfb79909fab23266813e365a31eb22c97233 381 10cbd665b73714436d358a6bfe7a4ec2bee76ec5dcd487b47792fa7adddd1dc9 382 903ae75e96fab2bb815a9e6b9826e314636ac4cdfbc341ff04da239c297eae0a 383 28a96fb45d4f455f1e93e2c6a2474684c1ed0352ac6b21076dbc50f3ddf7534e 384 f403c307f854a6b6b3ccd58d4b77bf34253aeeb1fc05c9780ce69b52822e15b6 385 038760ccdaa379d44227ec6b9b98ac4432ef6063533dd67bab0e0af9d619b831 386 45b458cfbb33864c4a95ed62ea25fcfd735f918905c356a36c21b636698e31ad 387 66f1c24d3bff3fe2c0be41bd3ec839148e396c399f4c8b3a3fad981c251de399 388 54b932a3f6809883875b7196664c12e1f71544f1983a624e1150f2a04602bd85 389 29332df3f33f363bc95fa2d66470b2f4f9a270ee394dad56f84c601ccbf00e79 390 52358d00b5d3b864e98e18259d860cc8cad4321bcb3c68335aca44a2ccbc9b76 391 5f07af7c1de5a427114dcae47a2e35ba5963db721dfa892b50bd616c84ded191 392 065ba96d4f610b414ceef9a2ddd5e1bac837f3d6d640968d0fb2fd46e3568889 393 7ebecf8e1ca763afdbb0374122be00d0fba3e7f6eb1fa274e5ef789c696bb12a 394 a0e53baaf321ce5191790d080e81b8fa4073768845fd5e653eb5755b1ea1b7c4 395 1d32c0f76cf806848989145254f9553554e1d54d84aa145dddce32ad2b764b1d 396 ad87ec995bf4acf2136c3e014c2d5a75204977b79150b9266ad5b4bffd43c7dc 397 f29fee35ea5abf21a7a010578cc245b1ca4a1b8c7584b859c8695ef0f7320b46 398 a79d270c21c2869f76bbeb6006dd2b38331ceb8091509533a93091845288926c 399 2260eb8de70b091ae664d7d054fcb649c6e3f8aea35c233738858bb0fc472e74 400 e69d2656c720eb91eb33a62e414b204d55c04c62ce569f912fd9ac3ceafac66b 401 b6d89635224d83ff477069b398c15d095965842e9d63bc725d227de20121b150 402 cb8afe4a9828e94bd20805a6a74fe979ea8ff11eb0b5ceb205587fa150a69335 403 45ebf078fabd50566e66603250812c66c8bb37fb576a712e29811cc1477b9e2f 404 72bbb8fe1402f3b2664a3c44e251b8a48abc1fdeefa606f99f4eed4302cb30ad 405 9d99ef23f26f44872b50f9d916d32355ce994fcffc451e43a24c528a90681221 406 23d81548e144fde00d9424bfdfda9bcbc22652bf0d8c4af371db88e2386bdda6 407 0b6680ae45d1aa98ad44b6c2b43e1338db918f93807b991c0efc59412c2deebf 408 02b54b8794e70dc4087e9f77a78bebf18699047f5027f58a2171afa1389a9b7d 409 ade6ec4b1921d9043da52fee611ad657f9b8f2680e56fa9205405db2027bc17a 410 b9e7cdacb5b36420d8a5a15af18e1bb57523191b8115a88829a43dfe7e9db248 411 3b30803f14fa977f3edf3f25a69c0818e7e0c589a968f6640aaa872455f10c61 412 b7502899272e744e1f8623213290ecd2afe68abd4b935e52c9200403dbc983ab 413 f478808522eaff68203759625ad88cc2f45878a53966aa8667755a13cc654cc9 414 eb5868f999f3c22fd65173dba83094aed7bc71668a4ccfe5ca242728225e1072 415 e9e4ae686163b452a396769ae9b20be6d5ee01aab182a334b8a6744d9ac45401 416 5117391136b2a3bc735b824a70c2e9446c0103450103b179717f89a44e80bc0b 417 6cf0b8bf4dfae7201fdf4b35c909e664afb129a3ce566f86d9b119b22a09a118 418 072bdffa44c7acb83d2b6182df9e1493bdb96967019f49b27fd62ee6fa3e8408 419 ae00ddc4f2f6337bd47336f68bb06d0c852d1e9f15e0b3cf12ad164503bc1973 420 5ebe6d52393d69f39364f91988da80955421dd0a71b3bf1c1e2f3142af2bc7a2 421 85f93c27da037246424652b60e1d23c20addf98d4a787136861204720ca452f4 422 24800f0508d291b7f5d4b0fb5e0ede27459737b03a433253b861f8760143b66d 423 ec96bfc69976ce2a044162e609680c00d626db5e066d03959367f0cc25e5d310 424 78c47cf00818ae74b7e3bdc6d1feaf6df94879531df6a7f57bfa2c965f11a335 425 9d2254f4d07e91b4975cd5259f6b71938d7688b91f5255b431d3af04fb59bf21 426 c6104a12cd1e94d3a05d16651089c5da8249efb23036d146366c6bda5620350a 427 ced280a5d480830fa959991f1b1b8aca552279976a3a0d036218f3b7964a826b 428 b670397263adb8999f2ebe751f4290ca3be020399a4d80a01dc9668244f13a5d 429 875ea5c4f7732b654dd0d9f56aebd8800baffedea2329df79fc1a3432171ec99 430 7c68e9329a8af919a18efb85367547fff6d9569fc57b732e0c5faab165244f85 431 e9ac6f17651e8c557497e9940afca6f723f9378b9d0c39dcefd416179fce483d 432 efe3dba790cd0f2d11dd7686bc0aba8dc76c930f1604dc72921cdfce8c65ef6e 433 8b1a1bae20b9ef3198fdd0e6417cdb023af49a1ab08f71a3074bf6c1618a22bf 434 01b8bd5f34844724002fb5695c791f74815a0b0cc4bd00e7f38fd915395ce50c 435 8cea0926c61ad953b8da9c680193922e5c240e6167089bd0146631bab05bb57f 436 2ac8eac580f29123d18b657a5e193c6e5227d2a0948ea0ee40db5dc1ebe6e7e0 437 fd6f2b8cb376eb3980a41b2ab4c05481173c347c5e5e208a24553ba1764fff51 438 170c3166347dbc60378b53b4a8036509efdc01f703537e0f16a950cf86e312ea 439 9dff54dd080ea96e7796523aa0852db0bf8262f3fdfe94e92b29b1a2e2adae96 440 7342940c595b2dde9210e7ba0d1b7b7ab0dc4688e781b3c1ffccbff08c0b400d 441 6c72217b279faa04914ade1f5ef586e3f3d18b34f9472f87cacfa8ba8a54ccd2 442 a7c7629a7cbef27aba51ca0818fd2bd804120f4f5a273ff7c4e9561ac55dabd7 443 d33734b3609c29d70a39e6c666f2a1ffa6f17eb14ba3c837e7cb07e7c4e5bec9 444 64bc70493a89cbbd96d03ba08a2e12ecfdd562e64bc4afed552ff3112cf1c7ea 445 c44e16c7c7cf18c9e411247b6240f8d46b54f20870c22256dd419e33aba9314f 446 79643dd3a0f2d6f09069dc78910c40356c8901e75c8638fa140b309c0a71786a 447 35204a0cf9518bf563c63b30a2dd97e0011f3bb67fd267431980665574c21887 448 6fa7dba3624f04ba76968af2d39ae257855b46fcb4a1f66c2aa80c4783576362 449 8b650b6e3393f7033c172a0162b6472c287cd4688b604ab88a63d06e588dc0cc 450 08c2a41d7a4635aeecb52fdedf0a166d80fefdcd99b2ef1fcc505de2a6ce1f2b 451 d51607ee699825a2ba1c476501bf95379aaba124d98476bfe856eeebc60f2f50 452 80b33e2559e4ab43e14219af206b018246ed40418f7c3755a0e4aca7e850a79c 453 ade81533befc027dab46b9548cac250b9d3034a9a22f2dc026400309e5a87a0a 454 c04b72827a56129d93251f6ef6687c46af06ecb9f519a6f6a60a7db4337e85e4 455 a39b828fc76090e06805713598feb837300a74db5a3e184e0ce0168f67a12d2a 456 aa85ff11d033de09bc8688e4c68d7bdc4750b00f7f53e673ce0113f3da0ed98b 457 7da09b33d14a7c6a10b16e4fcf3a8b396e79cf2c6a4a5c37bd64d152ce1af372 458 c3392bd482fa95f2828cc065e11c227c0f7726ea74e9b81fe168519ea86e4881 459 33ef631dc9ee13e16a8341b3389b77c9ac96a077eb025c397b8553ae67e5a601 460 f8ec0768cfe6ca2b9631215db704b5c0cc5d54e76f9d8374212e8abae7f6882f 461 96e695fad1fa3b09079db5757b0cfe7f373e0432f82f9918c942b7e38c14e0f4 462 cd1dfddb010b21962e9bf60a724b0bc305cffa7c1e5aa0df1328cd7df4f8237e 463 bf18003e70400851b672646131c18ffadd5b5094e849f7ef603351b94560af86 464 e4f14f29d25a90253ed8d97222afe09720ab29c110fb08a026b82e1f4e68988b 465 0ca3fdca85595405cfb25b24acc56c8a4ac9b4b51c6a24cbea9b4786ff062bd1 466 06d9bc4b6402042672cf9b21fa3085bc387388232c3722ec35bd3053d9e7dea6 467 b345cb8b50144380e7dcfcd4079fd78029c0d61faa0e97c62d9caf19dc296371 468 f31812afe2ab7828267b1c46054f35e61270014237c0280317773110b73c15bb 469 304742c2525fe7b587eb744e47718d59a8c887fbc2ebedb2d4a6a182a618bc13 470 0be68a837739bc62dff50fe8b25d61d0d737bae7ac3990a46a245ce5165ced77 471 47fba5559bd38d80a2c6cebfb0d2a64f22ab7ffa72c17e71ed71576e00d4ae7f 472 5cdfc77e4268c3a371739113c9be29d87ed47f193be51fea9b7a251dbbf5197c 473 5642505660b2513be2a026aff3a6b2b84dc4c18e185b8d088bd925822d04dcb5 474 478a60a17976b65461e5c761ad477218f0ddba3d7f671779601243a38aa47d76 475 26e04c7c0f878f525799bfa6f763f7e0464c9aedfff335480eebb32e9866b605 476 dbf17144baca7c668386ead7075b35a86595d12e07483be347df69507e20469f 477 aeb7fdf67be09ec0263597fdfa639d83bc972c29b9dc8086937171064cb0bc7d 478 a77690673453d91c1d1500ad188960e237db96644948870da5212bef41001625 479 b02526d172ca51b2e8a80b525c05efeaf0bb702b470a6405ce5b1556f39c8f92 480 ef34b132db16f28430c115c17b4ab441bbd957083eec1d3aecbd3f59392948f3 481 e966f1ef169aabb8347498837108acbdaf0cc23af7ed6955cbd9acf0eafbea2b 482 88507518937ed4ea09a737f50083789ab2af98c3e5b795c1920886123cd282b6 483 4f994986ef32cd4384bd647c47447a24a327e2eafbf848a88700aa6d6c624c49 484 787c5f77966a6959e433eef018fe431e811301a9cd0de10cdfbaf8007cb39444 485 70c47832b2bbf432b7b0e98e4271d938b20bc61b2af5e9b5aadf3d0adae35d87 486 9e9efc96f06725ece45d4db38233c7d12c073eb6d72bd68624f237813d0080bb 487 343eede66550f0fc30a819794931e2d5ec200895a2147b4899d116531d4ab6d8 488 dcf5dda42308a69b2c4675d3557bf7438e5d0692b9672fa7a884b2b9d5a6bee7 489 e2222d4fb0664d1ef153dbcf9e20d0183a3dc4b52f8dd62ea0d9bf124f3eb760 490 ec6641aa8633bf3ee484176bc5313690f591efa4cc737589396e42fb13d0a5ca 491 2e5dcfe85e9f569719bad9c9fd3524a0821be3dda1341c248aaab7e6b61b973a 492 ddc1c0beebb798c07327874e72244009b285f2d23d6e20e808ccc8601de3657d 493 cbe5d2f70596bf59bdb800881469ad367ac317ec97a8c8b2488ab7ca6583a31d 494 08bc849f0d7a1be7259f960586ee8bc04efa74886edb29a8521fe4c15ad33ef2 495 915b41f79da11445157da7d6fc0104c9cbc12244ac6ef310d8153753aeaf2d25 496 fa2b1dd71784f746de3fccb3342f50ff4e7215178285eda19dae8a98ac48d8bf 497 2fc8e2de5453466e900d3f9a9d5d382997462b819436e566ec5a120913a63996 498 0a88901cd21fd1068a2815778c9d801aaef4b6e22727ae07d0e5449f15db1f3c 499 7ac0661478c23018ea7244621a725c7340d603a01ba257af69cfc9e1310e4171 500 30d70cedda35e85f753ab2df08daad8ac6e7d9567fef87484492a5adcf58918d 501 0948b9198c6eaa39344770a3e87d3b8d4d7087aea19b84f1f6b6b14d27f599cc 502 d9033021eee60b75c1342f39af99f9ebb909801d6fc578403ee3b2cb177f24c1 503 4f5be35be976cca4edfb45aa97626314c5f49846b1b3c0915629ecbcd9d5441e 504 30e7d013a03215d7401a83c9f6da77a54c04adebd94bb9a4355de48cfc215051 505 c247f94ecb4f7116c70a3c078605a050acc869f2f705769f6c6047b907f56de8 506 aaa744a4f328cc7d5a39eb2344c17d7cd29fd5392a81c280d51a066e36ffb95d 507 4b2b8ff4dd702794e676bf115317b6100ca4a70ef07ea0f8f3517c24cbaa170d 508 6fca42197b2c192762f8ed00db8f56a072858d44e6ee4eab1d0ea98475838dbd 509 86d5325f84c56a6d29f8f5290f8652fa6f31daf7b237e54fc8be22113c19831f 510 e7d6e98f6a77879452d8b294449c13ce471fe4fa19e1d6205f4a9643c2b8d4e4 511 8b34a1bc499af46b25db9fe9c878e933eaca9546a3584da1a9c2e7ffc67f9651 512 49d44822689e85e475e52a8ba8bb1fdbae157ec7447a54d9db76ba7f84f517e0 513 aa06227892733188d219771317924fc0ea5ebb710c5b7d3227da879bfcf8ecc3 514 aa96ea9de117a5ece2216aeee4ba6b38cad175243a1a9264b5d4122ab3f7f870 515 59481ae98b00bec2132b86705afdffa87581777efe56f5053f4a8aa925a28244 516 b670397263adb8999f2ebe751f4290ca3be020399a4d80a01dc9668244f13a5d 517 875ea5c4f7732b654dd0d9f56aebd8800baffedea2329df79fc1a3432171ec99 518 7c68e9329a8af919a18efb85367547fff6d9569fc57b732e0c5faab165244f85 519 e9ac6f17651e8c557497e9940afca6f723f9378b9d0c39dcefd416179fce483d 520 efe3dba790cd0f2d11dd7686bc0aba8dc76c930f1604dc72921cdfce8c65ef6e 521 8b1a1bae20b9ef3198fdd0e6417cdb023af49a1ab08f71a3074bf6c1618a22bf 522 01b8bd5f34844724002fb5695c791f74815a0b0cc4bd00e7f38fd915395ce50c 523 37df224d115312ecff16ac2381a42393170300e36163c9c9e888882193a7c900 524 c9560dcfb5ccdee20af3fb858a01bb4d6093b805b48a2ed0c2dc3bda4410d8f9 525 b267992687669d8101eb1f4c07144b42e3c9838add8151e5a338dcd59756d4ae 526 d810adac53886516bb4a2a5f14891fe15c8d59df14b77f3115668d80e5594a3d 527 d10faa48f0d8ec7627f2cb80710b2c20653d7cb77aa05d74ab20048b126c2e41 528 e5ad75eb66eb44cad19a0089e4cfc55ad4123f18de58f8534e725ccdc64c7444 529 7f1af45b5c5502a3f75982a8ff582653225f851a6dbcbe0ba000aecabe1e84db 530 ea5e234abffeb6ae6f4bdd7aa522127a3c319629a5d9cc812b3a46630b7dd984 531 1a89e727b8fdf524e2e288f98b6a8bdece9557af565555d47122f480149d7a7c 532 e09500424d0797d2da4e93f6a4b4a6ec7b54a42de28525c9aea6b63b55499ee4 533 05c76a31c79e1b30acc84ae6ea226d539e1da89085ef3103c6e8a103ed5fca42 534 49d9af4d864f6214d0f55ae34e23b9440c61f6c1e3a48dd36396348dd4c0c067 535 8b4f57fc0afa637c8de7f8852dc6a9e90187698e36bb4455501a7a1eda5204c3 536 f99a9716374fa28edc7375e59e378b7f4c9fcf2a35f5649dd4cc0ebc9860478a 537 ecac15d30fa756da7625f3bd9a17b0273fb5bc57f56257d9b83dd4e5cc816e39 538 256df85b87579dd96fa1bd2616d182403d18313559377033b3cc28e50e96daf2 539 1b71dbfb881aac076ea08bafd4c8500ed0635d5cd2a06cc6cd76ca552d8df72e 540 5d211dc0beb1ed5704b0f77a6411f9a49a17d47bdda8ef3fad77ffc8a56c52db 541 ac203a5567a8ef5917466bf25c1f10f8cbae023369dd26b55848cd9854c2ce7f 542 a9e2fa7c85c107368eb46e1507169442820a7d633b692d899150fb924b4423dc 543 8541abd160651b9fc64b100cf6ee33675db52ff47e0de26fb93dd1c7d955eaea 544 e09a4fc8aa4db7f383d6db61794e30bde77f8b76a3344595821f087947c3f47d 545 f2816f56d2132f632be6b1d29dcd61ed1cc0c2b7e914f4e4168a3926e2a55a1b 546 bd31b91bd9b4af7ad9c2ac98f6ddb6fdcc6429353c5a98cbbb96e95528596b23 547 32f8820c16dd2c68dc174a50ad7359829cb93110741b9082bcacb321a5b6b9a4 548 71360363d5d30c748ae78dadf038c0b69957c66854cce0db06a6e297ca190298 549 488801462eff717330faa805053961c8efaaf67d7918167f8e15645dc917afe1 550 04b0e3dff6456ab88c1abb9b29d1b03b072a75312a8b4d7d1cb8a754c42c1a90 551 eb5ff50a0ce77467678d0d44a67ce3fa34af2c5b18b5fa38e74f79207167ef62 552 1725f94d3e6b448282af4b6c938601649354275c8aa99028f8ae28fad7c753de 553 9d946ed1621eaac87205e48371a400d2e9d5cf115df454b85c3284810a96d0a9 554 4c04089982bd24c3f571c10c4115618fc3b5269c52e701ce3236ac60959fc158 555 39ed2586b819e12fab16e9c66492acf6f400b4a83f4d4fe8c295f98e8be7f0ff 556 09941e8af43313d755b33e9532ea23fe71f816e0ed247aa0d9933f3886fbaf41 557 011850c5c1ef1e31b4b0232852401c3727da024a42d4617fc3338207ba08c238 558 6430a80df87d24518c34f3918cb91880fd86fcdc387b2678b015a8305ab42e51 559 9e7d9005a99f4b308a4d7022a49f895451ab272a42699836e79d8e25034cf23f 560 668f2e160cb83862cf5c04054ee05490c1782b393cce526fd1a9a644e42ce762 561 6bb3bc9c8a6b3abe7c131ba4b642bcc821580792cfdc223a0506f2f3ef9e8403 562 020bb6a082830f6c95e8b0f46d144b75daf08ba7554b43eaedc64ee83db8b8db 563 6716c76864a522f2aa9574b0c56708c48bf011b1d7e459e4ba1c176898922b44 564 018c4e797c6ebcaeb762ee0cb467a5bfcaabf034b16ce81b44f480f51dd19073 565 6560ddb8e5f033a8bc0e5c5ce4b4c8d8db3eb03e0d95f45e66fd8cfcf2c0cd21 566 4428f085422fdfe696dfdcbf3cde2e8c6a623127d0c54570fc4a8ea9b5b34257 567 ab657fa9355099c6360b66aa0231cf7a601558757a468d109ab162a47423c53e 568 45b1db877786c79be6790fdd32db61661b5715a3b203ba1de888d7925b0bbfd5 569 af0d3a9f9f897b8dcd4e8b86ee9d6f66f07e68b5c3f7e68adb6092b15e7be81f 570 96ff0565bd553d06655630ed7b32a43fcc5c36bbd907e8038edd452e029b12b3 571 08e0b6e91e69460a848e180b50f8d780a9c8f42ae356cecdaaf067a07691b6f0 572 7507dab48eaf193f2aa36c93163748e88de4bc9035295b558804ccaa3d4aa586 573 64806180bd4c2f3c0f63996647d1538b8eea005fac7b46441730f8f6fcb6e4a3 574 353fd1d518c5e4ad47f0fa18c4326a55ff3e13f0f9d86b8a49aa1f005a4f541e 575 06e750f27b016ec19c3631b6c183b804e3b20d62dee8d79f4aa1abbab2520c48 576 bef8374b5bfa10bb6608c39e018c060152fd96a0af6cccc8b925d2a77fadf5f2 577 4b31771a3d55456be84d8362b19da116be70c0683dc2c4a4879b0de7bc9b6cbd 578 a746d2220afca3b6a9551bfd5454276382fdabc5dc0f552ede88122f5fe259e8 579 65e8cbc018f72badda5097bbe19b7f2325c450c39af003f4ca14c9801e49f957 580 f3ca67f85aa83199c5e301f49fba46b331c3ac43ae88d44944ecbc4ba6eae3ea 581 851bf5d90d6e7d706c4dc71fb17f022cfcbce9cb05f456b20fbc21a3b771fe09 582 66eed59ce3647171eae59a9e131d56b562a7179f2a1e15462e73c93be9e29f1d 583 24aaf4cf9c640c68d02738d365954d7c3193f95ac36394b6d71213c1ad73d0a9 584 2f54a0d6f8dca05c7e5a53437d2bea6d66063d6b2a237d7a56482b897a398813 585 101db3aea01e845e6cc44de97ee50754da625a4fd22886497f00803985893d19 586 644a31f2b268cd2c0c5df4968f41c86ede117acd13ec3ef242f1e2d165cc139b 587 8948431a3cf157f2dc29ab954647baebd9006baf6a6b8574b00e389fb0079fcc 588 87dfadd16e4db014c8ea209325fb3e7712cd7c0f2dc4786ac54f6533762739aa 589 dd9b42d690617bc03f2992a48f78935aa2c56184556e0154a8ef63b67eb6bdbc 590 2d7e1e4dd8238b1a5e2b3dfbb2408ce907b75497758fa1e774f9a9faf84e0664 591 f39826d08bdfbf7c3bf230ad10423ff685884e3708a840149489e48bc9008179 592 f88666fa3b52e56a7e683124218d5a9041b9cc046882d3857fdc5a60c2d5d9fc 593 8c00069106a5c035583dcbb0a90c22349e1fb2d5535f85137aa9489738f18817 594 04cfe6410e3ae2c9441c72bd5b32e1426f8d9a932ee7639ad917642ff652f631 595 eb65f6588ac828804add48f69a77e8dd84d74339b77a568a47bbddda6d7ff4c5 596 c446ed2ace59998a75f512b8b6f3f9da6652cae631b2a8d5c00d258dd957efb1 597 274dedeaecae1966a733812ed09bb54ca77150f29df099643d7e190d477e7fab 598 f4abb163022000847a9231d54ea3cae2c583a2162cecffdac6fb741e0cba71aa 599 279bd564894dc7665b98b6046fe7f815beca5fc91975ee517e7c24e3b222f433 600 aa85a0a46c9c977b137bd6b4b279c9dc011dbc923d365d59b08aa32367b708e7 601 fa4d41f0a730ea78c9e8746bb0040f8a43a23f6507f2863551e237de7ff7422f 602 032235f224118623d457aabb6ffc78a3401d20260e7efc97a79614d556a255c0 603 f4d311b1a6787d49e7e3501f258eda001d8df0163ba945211ab0e5b9730e329a 604 ae2638906fb6ea273839a0ee7b1032dea8356d206d93f27a277046df3f1a11f9 605 9a97ba16046767297bc8975c0c3b1589c5f801d225a592f9adadde68470fa4c3 606 711ab6ed6c8ec2165a1d050500aa244b2f1f3a5077e3b5895408e2b3f84917c7 607 3f4f5b42b196b482972ddb1fd0e5548451c9bdbf0516dde56ef445ed17a586dd 608 6555b878d88a2eec68e1f501e2dfc152c655e90ac20fe9267e0c5900c3b7e1fc 609 44f91407d419f46b7f988ffabbbf033d1f73186c3152ebbd99f8aaf98be3b696 610 0563ecd1072777b437e68378928821d4717ef7c9a9b9b935ab9a908d5e82ea0c 611 9a8b306fa55a813ed3bfaa71deb793018be40c5d0127828687ee846f2e14593a 612 08c39cebc309efe4e95a4dfabe376594ffc973f11641516ac431781b09a90af2 613 b9c45a4b524af92340f12657ac3715de35f002d74f87bb6cb34ba1c48e5ac69e 614 888604f53c1f231d29a45f8117bc27d22f0fb34f6028ecd221ba2af787efc592 615 1dc0abf550f65d2993aa7de018ee54a4d6b92a7794963bf4d7faade794aa269c 616 cbc8c340251d716ef1713b2934bce59455747c22445a7901e8570c2cbd3b2109 617 9ec8b13f366c35f68c5cea855a06a524aa1f217a3850e5cbf1029a048243d272 618 7d2f749b7996ad212c06ce27f9da7aaca64c613bf7c793557ff1cd5ac77156a1 619 aec365f9671abd15ff31d4ea00ca06a35e4a8418a8d77f7bb61bb064123ed262 620 8541abd160651b9fc64b100cf6ee33675db52ff47e0de26fb93dd1c7d955eaea 621 e09a4fc8aa4db7f383d6db61794e30bde77f8b76a3344595821f087947c3f47d 622 bb3916b251ef2a66641a8150ec0262619fc63e27327f82de904a969609060c8e 623 282593572f2cc56b5ec6cd740f45325892258d75257aa6fe08fda0a055258e6f 624 be30cc258cce6007c2d666e2d5214164891c3944c478d19289e23e7e05ff1505 625 f1788fc46a65352f5ac1f286e69ed0219ac78832b5f826c9cc9f21f489f5d047 626 96e695fad1fa3b09079db5757b0cfe7f373e0432f82f9918c942b7e38c14e0f4 627 cd1dfddb010b21962e9bf60a724b0bc305cffa7c1e5aa0df1328cd7df4f8237e 628 bf18003e70400851b672646131c18ffadd5b5094e849f7ef603351b94560af86 629 e4f14f29d25a90253ed8d97222afe09720ab29c110fb08a026b82e1f4e68988b 630 0ca3fdca85595405cfb25b24acc56c8a4ac9b4b51c6a24cbea9b4786ff062bd1 631 06d9bc4b6402042672cf9b21fa3085bc387388232c3722ec35bd3053d9e7dea6 632 b345cb8b50144380e7dcfcd4079fd78029c0d61faa0e97c62d9caf19dc296371 633 f61fafba7586c7a8e62fee0368d254eded452e050c1eac7ca689548984bffff1 634 73aa1c45ee864490c1c5dd3f34149199afd0ab5c57dc1e809e9465a9806d630f 635 40099f4ba6502b574ee6df0edb45eaa3edbde18c6e0406aec1641d6da7460ed8 636 9da87b58d6cbc247f2470b22c6ff2075075fe1ca245ac37b893b700a7f4397aa 637 15761b09580408fc2b06c473b5e401158b0d65c29b189912ef381230f7e8379e 638 075c998b827b71bcf6bf63ed9b8a27825074bdebb7b96b0ca7860bfbe6b8b043 639 9eb6334d414a87d461572731b6e1a7673ddfc0fee3b5efed043eac6ccfb92550 640 9691f16d9e598e891a75f4f7d23a46d71716ba188d6a46aa4873b5e6efd086d1 641 0dea28fef2b1635c2409dc3a1a357240b67daabc139f64d257d4db02a5319297 642 8c27ee8e304e15e4c3df9e52c42792d5dcb7716a198b03e6cb6802d9c0f60b2d 643 43ff7df5605fde04f783b301ef4ef2ccf45a4adb99093d33a9b552ba2d326f6f 644 a3ffec16c3c99d13aab85a94ece00502f51324639e6605e4fc10b7d24e804501 645 da20880695cbaf0d60c29a8ee2edb4e31bd2276f7fdc93fdc0a44100bb18d71c 646 aa64b47eea96aafb1338eca27739c2d9658db1e5d7f513a98607c15ffad5e3d2 647 ee0ca1013ad27917e0c0bcf424485e9e4374fe23e2a340c22c966488250c0074 648 4e7be40845d23ea88b7cc266330bfded2a5a8313973b43050b4b1c618fe70c5f 649 83281199716bcfa7a5cde30b8df22d0bb1daa443df660df8efbce56c1fb902e8 650 77398755b5f97f88479923b78d490779f0246f22b9c71cf3cea0e2032b64f341 651 ea387df1ae4b48984dd9ee676788ee55874883a11b4e22c845c7884812865d72 652 19d46936d2f4b9d207b5ccf27dd20aed14d871c74bd2f70dcffba7e7a6d2be1d 653 d4cb0241a5350fdaca5a886dc6ef357efa48c901cd88c077375703a36e15b19f 654 aa07325cb4bcf7679cc1f63892605fc89a3c21a967341783a650646824093505 655 ad29d1a09dd649aa3d4fd1a13cdf697565bbb4628b97c79210e9bdae0db6a490 656 646c8ec5b787e39694e82ff6a2c9f4b9f93579b53ddab3eeca772d56990594cb 657 6b22a709fa31a04893c360f7f199d2ab0790eeb0f7acc673a01b9fba38a3448c 658 70c3cc71127ffcfaaf8869e6926424bba74270f8c9d807c6539e66322953916a 659 b0cd21c569ffc5e78a8b20c7c97e80f4dded31e898b2dc2937d3d36825d373f7 660 136fc93b665d0fa41b8e9af3f45826d3065678929e259181aa2a1fafe4ec2386 661 675fbd7fd90390eec2c34acdf5e8a0986fcf4816f6a297e0742ee635689bb4b8 662 877b081c73e961c94b6dd98701023424aaf9c4d999466e524d244361691df535 663 e9ee78eaf2027cd1421cbc7071d6de0abfa150a3d4ac2a0b21dca61f11d71995 664 38f9c648e044b02d12263d67a6930732833af46b42f7e8e20d6a3ee3271a7b85 665 c867e4bfc0d0b97d0ce2216b91fa2cdff2b12dd29f35dd6d514a8e8f66873451 666 217a860f780649da1ccb8b8e256d342f242545c74924e4cdbb210c0b92a60f9e 667 97fd6931ab0866855612316a2ec933df0c13f6b4470a3571c1532edebf3ca23e 668 9afd86b968386306ef98faf091f308560ea282d4f085881ebf347770c9b26f01 669 e69b2f72e36f6d8e91b3baf408068db268c98a92801c8e44f9e25575b4d00cc1 670 0ff51d46b074db962132a1b29d610b1f6c2fbe0ad75e1586ed1a8aa1e958bae6 671 978827d644d4ba866e17f09b1ee03d7ebdfcb9e821685435675fd429c63ca993 672 cc97c066094972bf7ecc26a88a7c4c4b611cd6a17b98dae5958f9461bbd429a7 673 a11cadfd66eabd80ca390ca6aa2a5412318e0cb9e3ad40123900938b77b4a64e 674 712699cd25a240a8e8f8b02efcee86b3bec3ef1d43049b5fb44072396b75208b 675 28c109075e80a3dcca6eea3a8eadb5216522f3118b1ac556665643408f1c64a1 676 3f4574d8364334214a42011a49399d396a24636d7f49def9be1641bd56f9f489 677 28c0cb5f3096dd830ed1ede5aa27c4f8e631100f7359fbcf999c05db47d82964 678 7eecb5477d1309d0daf02ba6fad2eacce7d637226e438d7e8cd69ba0eec1715f 679 f485f2e83fc5c6eba046349d6a43c449dfdc1bf7461b98b7b7a2982adceae153 680 1d0847c1e5ee89dc1b5c88652c79247b3c8dadc23ae0530f4a92ab3292b66819 681 2931c96107fc8afbbb93d796d6837eca27d7797fe945802287ffbd96a9d048b2 682 765c9bd346d29b04bb038cd3d6203cf6f8e8682f06c7cfe0a21817d4bfc2f1f4 683 13fc96fdde7c30d1f6d524710d82db17d1e43287e3f5c7fac781d20d0985d2b1 684 ac8c58ae078265151f5f44c0adc10e4f19f0a4230fea07d694607e4be850286a 685 0a88901cd21fd1068a2815778c9d801aaef4b6e22727ae07d0e5449f15db1f3c 686 7ac0661478c23018ea7244621a725c7340d603a01ba257af69cfc9e1310e4171 687 30d70cedda35e85f753ab2df08daad8ac6e7d9567fef87484492a5adcf58918d 688 255ae3c9e1a8e3a52312bc1c50918a809f02176a2709e4c9f08347512a1ecb18 689 527db41d74556c30853e3528d1afa73aeaee70c382a824050634ce154a9e53b3 690 dbd850c7ab225adee604bedda2bb92b7716dae0b4bdf376a26dbe367de789761 691 9846facd40cddd195cf0da397837ec034cc3389e35087ee3a04224b539ea8470 692 3c5b4b7ec8ed92e371af95082591ccc39924eadf827cb901f9a0a77c24d20df3 693 f7ac968779cadf47750dd162561f14ea9a6eb0ceda92ee800cc66b66a42db94d 694 0baa7a47587e11e6481c62c014ec495be5d484005e32138a1614ae2732a206e6 695 9691f16d9e598e891a75f4f7d23a46d71716ba188d6a46aa4873b5e6efd086d1 696 0dea28fef2b1635c2409dc3a1a357240b67daabc139f64d257d4db02a5319297 697 8c27ee8e304e15e4c3df9e52c42792d5dcb7716a198b03e6cb6802d9c0f60b2d 698 43ff7df5605fde04f783b301ef4ef2ccf45a4adb99093d33a9b552ba2d326f6f 699 b0f80c3b602eea71a01970684d4c281d3592c6faf2622b29838c0c1853b8a16b 700 c622f80755993af1e809b47e9b10eea6f45a2cb024eb4177011d2978f0509247 701 96283af67955c1647dcb34323b3e92255cf07a6e295df1b064850c1c7f9cc4a5 702 eb5fc40ab46f94a0cfb7833c7fe710bc79923512dc29d77ba6955a0ac5ee303b 703 ec7946476fddaf3cb2e6429d806094cafa6baee1dab6afa0c70dbfca2d0eafe4 704 8c63b8784cd09a68defdc5aa3b9451b585384cbb2bd77b9243c238adcdcec4ac 705 94e5bfd53d89a90c8267a88fb3f668caac92a391eab301c82cb0a7463e75b5c0 706 0882acb5a9abd54dd16592080a61e4a1bb269daf046a3bed0c2ee81cf3a6ba5b 707 03fc9f609592914aa9a1c0709737fdb02be505a0848576284e1f7356049f5f11 708 73baf878429c35a6e77252963af1f67f77c535ddd65b2f262a405f1b86ecd0bb 709 8059668f902a183b8c047c3b6ecf1c5ecf0dc856872d4c6de862460ee7207bfa 710 5fec005d96fb7247383e39919b961f312fa9181b917dd8b2908df6fa25d415bf 711 82dd9bb441dda31b7bcdd37d0cd10ab7b11ae78db0881a4bd9896e681cd4aca1 712 fe631b398508c77e5f3cbcc83b17e6c287822985d418888f9de8be50643611fa 713 23d57c463d2d6b44e2369618fe03a6b12fe9d1a343976133853df91abec50501 714 8c00009de7b504084362dfe34c41fe04c34e7a46ba6a50e204ba000319f6ce3a 715 fe40a9a3570b441caace107d4c16584cb54ffdb40a2d47b655749c820bc47940 716 f1eaa893d08a863de323f433b27235649a4dedcb52d842e70493169a0a7c413b 717 62ccf45293e28afea04b7d2248b777dd47d2a15a6548ea81b831418902cf7d20 718 2f4d3cc94eb04c407b2761ffaf25e7af7fe91b2e1938ce4b6e3cc386d3dd8c26 719 223d42b102e2c4e84970aab3a792f72a897cdeae385e2c4026c3c04d922df7f6 720 d36e96d90cc50c414b1108b9a9c9987711e9c0fe08dcf8ba572fc94d60c06c9c 721 1472964582bbb7be1cd233dd907da6a7630319606bf886fdd2be76b07d1f5e72 722 e022431874358e0c2950666fd5a01167537c6d437a96af81f0e5715ae7c66b4e 723 114172e58bd30b6de803060719b07c112f2f6fd3c5ca20218901789a26daa126 724 48008dd14397fb6986f436072992c66c43cee485be76273b9a1fa11d8ea5b3d3 725 d8abda41080db55fa6099321181c7964b027276af5a1ecc193a3d58b1218e46d 726 c72ed2535e8c4112774c8ba2f1736c22c142f1760fede5373753b8d6aabe70a7 727 2dfe888a54cad937e0d6769d539754aefc42214c5589a66bb2b8f40874c377e9 728 ab352e59601ce0c3944bc96138d69d70f3b0fbfcaa371b8ec484adc8e3c38b91 729 e5359fa436a32167c12c2d18820eded1804119d71bdd1ffb60ed7a2dd3e8aee6 730 b0ce7bf6d5e91ba685dc66a959c94b67cddc396b75ef9318fe58bae5c5f3b480 731 2e8ec7a669098d237e18390c1db9371f8c98508d0f713a1252147a149a982c2e 732 9df3d5d613420485d187a116aea86c3578fa466dbbef1374f5ba26a053ddda8f 733 0e77e6ba98f41c8a9852d9c93dc303eb4588286855db890897ba49c720a3fdb4 734 33e284110dd0b62093554ede883e8ca8c1be572e96d99f1819caff2408b3d91c 735 daba1543d899b5f51667176dfdd03fa79e2013f9522bd7d0a48051ad467a4beb 736 58e9357a34882956ff5d3a62eba8290f4210a2387bc0c3ff14d544ddf0844c70 737 fa76092b19c08e6234b94231f1c1e831ad4d9c2680747e1406812434191e6b1a 738 0740816fe0b46ad7b7175fb80f1358bcafcd368d4b69f37779d212b9b5b19974 739 c2789cea781451815fb404642aee289cf52bed0b50ebfa2c2fe81cc5e516a5ab 740 2dd2e07884e0ccb502d75c403145b6990c2c1394c79fc30d97c3209e917919fb 741 a6f3d46af8fa03d49676d11331305e8edbc5e76d6ae5dbbeacb157b7d9289933 742 b1b243c598d750de4f8fb1be1c55625780201b6faecb3d71bcc5da9ae790207f 743 "; 744 745 746 assert(sig == expected_sig, "HORST signature does not match the reference implementation."); 747 748 auto verify_result = Horst.verify(msg, sig, masks); 749 750 assert(verify_result.success, "HORST.verify failed"); 751 752 string expected_pk = x"b9b7d899ac95e7bbca810c96c01d0735d92c4e8a0724c7fa5486ac7463ca9751"; 753 assert(sign_pk == expected_pk, "HORST.sign generated wrong root hash."); 754 assert(verify_result.root_hash == expected_pk, "HORST.verify generated wrong root hash."); 755 756 }