hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 1370474fdfc474957d099522c0666a6de1d880e3
parent f83be846d469d7a42a4dc237c136c8a7d1efcb80
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Thu,  9 May 2024 13:31:04 +0200

crypto::ecdsa: add testcases from RFC 6979

Signed-off-by: Armin Preiml <apreiml@strohwolke.at>

Diffstat:
Acrypto/ecdsa/rfc6979+test.ha | 398+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 398 insertions(+), 0 deletions(-)

diff --git a/crypto/ecdsa/rfc6979+test.ha b/crypto/ecdsa/rfc6979+test.ha @@ -0,0 +1,398 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use bytes; +use crypto::ec; +use crypto::sha1; +use crypto::sha256; +use crypto::sha512; +use encoding::hex; +use hash; +use io; +use strings; +use test; + +const p256q: [_]u8 = [ + 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, 0xeb, + 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, 0xfa, + 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, 0xfe, + 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, 0xbc, + 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, 0xc2, + 0x94, 0xd4, 0x46, 0x22, 0x99 +]; + +const p256x: [_]u8 = [ + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, + 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21 +]; + +const p384q: [_]u8 = [ + 0x04, 0xec, 0x3a, 0x4e, 0x41, 0x5b, 0x4e, 0x19, 0xa4, 0x56, 0x86, 0x18, + 0x02, 0x9f, 0x42, 0x7f, 0xa5, 0xda, 0x9a, 0x8b, 0xc4, 0xae, 0x92, 0xe0, + 0x2e, 0x06, 0xaa, 0xe5, 0x28, 0x6b, 0x30, 0x0c, 0x64, 0xde, 0xf8, 0xf0, + 0xea, 0x90, 0x55, 0x86, 0x60, 0x64, 0xa2, 0x54, 0x51, 0x54, 0x80, 0xbc, + 0x13, 0x80, 0x15, 0xd9, 0xb7, 0x2d, 0x7d, 0x57, 0x24, 0x4e, 0xa8, 0xef, + 0x9a, 0xc0, 0xc6, 0x21, 0x89, 0x67, 0x08, 0xa5, 0x93, 0x67, 0xf9, 0xdf, + 0xb9, 0xf5, 0x4c, 0xa8, 0x4b, 0x3f, 0x1c, 0x9d, 0xb1, 0x28, 0x8b, 0x23, + 0x1c, 0x3a, 0xe0, 0xd4, 0xfe, 0x73, 0x44, 0xfd, 0x25, 0x33, 0x26, 0x47, + 0x20 +]; + +const p384x: [_]u8 = [ + 0x6b, 0x9d, 0x3d, 0xad, 0x2e, 0x1b, 0x8c, 0x1c, 0x05, 0xb1, 0x98, 0x75, + 0xb6, 0x65, 0x9f, 0x4d, 0xe2, 0x3c, 0x3b, 0x66, 0x7b, 0xf2, 0x97, 0xba, + 0x9a, 0xa4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xd8, 0x96, 0xd5, 0x72, 0x4e, + 0x4c, 0x70, 0xa8, 0x25, 0xf8, 0x72, 0xc9, 0xea, 0x60, 0xd2, 0xed, 0xf5 +]; + +const p521q: [_]u8 = [ + 0x04, 0x01, 0x89, 0x45, 0x50, 0xd0, 0x78, 0x59, 0x32, 0xe0, 0x0e, 0xaa, + 0x23, 0xb6, 0x94, 0xf2, 0x13, 0xf8, 0xc3, 0x12, 0x1f, 0x86, 0xdc, 0x97, + 0xa0, 0x4e, 0x5a, 0x71, 0x67, 0xdb, 0x4e, 0x5b, 0xcd, 0x37, 0x11, 0x23, + 0xd4, 0x6e, 0x45, 0xdb, 0x6b, 0x5d, 0x53, 0x70, 0xa7, 0xf2, 0x0f, 0xb6, + 0x33, 0x15, 0x5d, 0x38, 0xff, 0xa1, 0x6d, 0x2b, 0xd7, 0x61, 0xdc, 0xac, + 0x47, 0x4b, 0x9a, 0x2f, 0x50, 0x23, 0xa4, 0x00, 0x49, 0x31, 0x01, 0xc9, + 0x62, 0xcd, 0x4d, 0x2f, 0xdd, 0xf7, 0x82, 0x28, 0x5e, 0x64, 0x58, 0x41, + 0x39, 0xc2, 0xf9, 0x1b, 0x47, 0xf8, 0x7f, 0xf8, 0x23, 0x54, 0xd6, 0x63, + 0x0f, 0x74, 0x6a, 0x28, 0xa0, 0xdb, 0x25, 0x74, 0x1b, 0x5b, 0x34, 0xa8, + 0x28, 0x00, 0x8b, 0x22, 0xac, 0xc2, 0x3f, 0x92, 0x4f, 0xaa, 0xfb, 0xd4, + 0xd3, 0x3f, 0x81, 0xea, 0x66, 0x95, 0x6d, 0xfe, 0xaa, 0x2b, 0xfd, 0xfc, + 0xf5 +]; + +const p521x: [_]u8 = [ + 0x00, 0xfa, 0xd0, 0x6d, 0xaa, 0x62, 0xba, 0x3b, 0x25, 0xd2, 0xfb, 0x40, + 0x13, 0x3d, 0xa7, 0x57, 0x20, 0x5d, 0xe6, 0x7f, 0x5b, 0xb0, 0x01, 0x8f, + 0xee, 0x8c, 0x86, 0xe1, 0xb6, 0x8c, 0x7e, 0x75, 0xca, 0xa8, 0x96, 0xeb, + 0x32, 0xf1, 0xf4, 0x7c, 0x70, 0x85, 0x58, 0x36, 0xa6, 0xd1, 0x6f, 0xcc, + 0x14, 0x66, 0xf6, 0xd8, 0xfb, 0xec, 0x67, 0xdb, 0x89, 0xec, 0x0c, 0x08, + 0xb0, 0xe9, 0x96, 0xb8, 0x35, 0x38 +]; + +type hashf = enum { + SHA1, + SHA224, + SHA256, + SHA384, + SHA512, +}; + +type tcurveid = enum { + P256, + P384, + P521, +}; + +type testcase = struct { + curve: tcurveid, + qpoint: []u8, + x: []u8, + hashf: hashf, + msg: str, + k: str, + sig: str, +}; + +// XXX: alloc is used to circumvent not initialisable during compiletime error. +fn rfc6979_cases() []testcase = alloc([ + + // Test vectors for P-256, from RFC 6979 + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA1, + msg = "sample", + k = "882905f1227fd620fbf2abf21244f0ba83d0dc3a9103dbbee43a1fb858109db4", + sig = "61340c88c3aaebeb4f6d667f672ca9759a6ccaa9fa8811313039ee4a35471d32" + "6d7f147dac089441bb2e2fe8f7a3fa264b9c475098fdcf6e00d7c996e1b8b7eb", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA256, + msg = "sample", + k = "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60", + sig = "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA256, + msg = "sample", + k = "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60", + sig = "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA384, + msg = "sample", + k = "09f634b188cefd98e7ec88b1aa9852d734d0bc272f7d2a47decc6ebeb375aad4", + sig = "0eafea039b20e9b42309fb1d89e213057cbf973dc0cfc8f129edddc800ef77194861f0491e6998b9455193e34e7b0d284ddd7149a74b95b9261f13abde940954", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA512, + msg = "sample", + k = "5fa81c63109badb88c1f367b47da606da28cad69aa22c4fe6ad7df73a7173aa5", + sig = "8496a60b5e9b47c825488827e0495b0e3fa109ec4568fd3f8d1097678eb97f002362ab1adbe2b8adf9cb9edab740ea6049c028114f2460f96554f61fae3302fe", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA1, + msg = "test", + k = "8c9520267c55d6b980df741e56b4adee114d84fbfa2e62137954164028632a2e", + sig = "0cbcc86fd6abd1d99e703e1ec50069ee5c0b4ba4b9ac60e409e8ec5910d81a8901b9d7b73dfaa60d5651ec4591a0136f87653e0fd780c3b1bc872ffdeae479b1", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA256, + msg = "test", + k = "d16b6ae827f17175e040871a1c7ec3500192c4c92677336ec2537acaee0008e0", + sig = "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA384, + msg = "test", + k = "16aeffa357260b04b1dd199693960740066c1a8f3e8edd79070aa914d361b3b8", + sig = "83910e8b48bb0c74244ebdf7f07a1c5413d61472bd941ef3920e623fbccebeb68ddbec54cf8cd5874883841d712142a56a8d0f218f5003cb0296b6b509619f2c", + }, + testcase { + curve = tcurveid::P256, + qpoint = p256q, + x = p256x, + hashf = hashf::SHA512, + msg = "test", + k = "6915d11632aca3c40d5d51c08daf9c555933819548784480e93499000d9f0b7f", + sig = "461d93f31b6540894788fd206c07cfa0cc35f46fa3c91816fff1040ad1581a0439af9f15de0db8d97e72719c74820d304ce5226e32dedae67519e840d1194e55", + }, + + // Test vectors for P-384, from RFC 6979. + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA1, + msg = "sample", + k = "4471ef7518bb2c7c20f62eae1c387ad0c5e8e470995db4acf694466e6ab096630f29e5938d25106c3c340045a2db01a7", + sig = "ec748d839243d6fbef4fc5c4859a7dffd7f3abddf72014540c16d73309834fa37b9ba002899f6fda3a4a9386790d4eb2a3bcfa947beef4732bf247ac17f71676cb31a847b9ff0cbc9c9ed4c1a5b3facf26f49ca031d4857570ccb5ca4424a443", + }, + + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA256, + msg = "sample", + k = "180ae9f9aec5438a44bc159a1fcb277c7be54fa20e7cf404b490650a8acc414e375572342863c899f9f2edf9747a9b60", + sig = "21b13d1e013c7fa1392d03c5f99af8b30c570c6f98d4ea8e354b63a21d3daa33bde1e888e63355d92fa2b3c36d8fb2cdf3aa443fb107745bf4bd77cb3891674632068a10ca67e3d45db2266fa7d1feebefdc63eccd1ac42ec0cb8668a4fa0ab0", + }, + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA384, + msg = "sample", + k = "94ed910d1a099dad3254e9242ae85abde4ba15168eaf0ca87a555fd56d10fbca2907e3e83ba95368623b8c4686915cf9", + sig = "94edbb92a5ecb8aad4736e56c691916b3f88140666ce9fa73d64c4ea95ad133c81a648152e44acf96e36dd1e80fabe4699ef4aeb15f178cea1fe40db2603138f130e740a19624526203b6351d0a3a94fa329c145786e679e7b82c71a38628ac8", + }, + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA512, + msg = "sample", + k = "92fc3c7183a883e24216d1141f1a8976c5b0dd797dfa597e3d7b32198bd35331a4e966532593a52980d0e3aaa5e10ec3", + sig = "ed0959d5880ab2d869ae7f6c2915c6d60f96507f9cb3e047c0046861da4a799cfe30f35cc900056d7c99cd7882433709512c8cceee3890a84058ce1e22dbc2198f42323ce8aca9135329f03c068e5112dc7cc3ef3446defceb01a45c2667fdd5", + }, + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA1, + msg = "test", + k = "66cc2c8f4d303fc962e5ff6a27bd79f84ec812ddae58cf5243b64a4ad8094d47ec3727f3a3c186c15054492e30698497", + sig = "4bc35d3a50ef4e30576f58cd96ce6bf638025ee624004a1f7789a8b8e43d0678acd9d29876daf46638645f7f404b11c7d5a6326c494ed3ff614703878961c0fde7b2c278f9a65fd8c4b7186201a2991695ba1c84541327e966fa7b50f7382282", + }, + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA256, + msg = "test", + k = "0cfac37587532347dc3389fdc98286bba8c73807285b184c83e62e26c401c0faa48dd070ba79921a3457abff2d630ad7", + sig = "6d6defac9ab64dabafe36c6bf510352a4cc27001263638e5b16d9bb51d451559f918eedaf2293be5b475cc8f0188636b2d46f3becbcc523d5f1a1256bf0c9b024d879ba9e838144c8ba6baeb4b53b47d51ab373f9845c0514eefb14024787265", + }, + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA384, + msg = "test", + k = "015ee46a5bf88773ed9123a5ab0807962d193719503c527b031b4c2d225092ada71f4a459bc0da98adb95837db8312ea", + sig = "8203b63d3c853e8d77227fb377bcf7b7b772e97892a80f36ab775d509d7a5feb0542a7f0812998da8f1dd3ca3cf023dbddd0760448d42d8a43af45af836fce4de8be06b485e9b61b827c2f13173923e06a739f040649a667bf3b828246baa5a5", + }, + testcase { + curve = tcurveid::P384, + qpoint = p384q, + x = p384x, + hashf = hashf::SHA512, + msg = "test", + k = "3780c4f67cb15518b6acae34c9f83568d2e12e47deab6c50a4e4ee5319d1e8ce0e2cc8a136036dc4b9c00e6888f66b6c", + sig = "a0d5d090c9980faf3c2ce57b7ae951d31977dd11c775d314af55f76c676447d06fb6495cd21b4b6e340fc236584fb277976984e59b4c77b0e8e4460dca3d9f20e07b9bb1f63beefaf576f6b2e8b224634a2092cd3792e0159ad9cee37659c736", + }, + // Test vectors for P-521, from RFC 6979. */ + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA1, + msg = "sample", + k = "0089c071b419e1c2820962321787258469511958e80582e95d8378e0c2ccdb3cb42bede42f50e3fa3c71f5a76724281d31d9c89f0f91fc1be4918db1c03a5838d0f9", + sig = "00343b6ec45728975ea5cba6659bbb6062a5ff89eea58be3c80b619f322c87910fe092f7d45bb0f8eee01ed3f20babec079d202ae677b243ab40b5431d497c55d75d00e7b0e675a9b24413d448b8cc119d2bf7b2d2df032741c096634d6d65d0dbe3d5694625fb9e8104d3b842c1b0e2d0b98bea19341e8676aef66ae4eba3d5475d5d16", + }, + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA256, + msg = "sample", + k = "00edf38afcaaecab4383358b34d67c9f2216c8382aaea44a3dad5fdc9c32575761793fef24eb0fc276dfc4f6e3ec476752f043cf01415387470bcbd8678ed2c7e1a0", + sig = "01511bb4d675114fe266fc4372b87682baecc01d3cc62cf2303c92b3526012659d16876e25c7c1e57648f23b73564d67f61c6f14d527d54972810421e7d87589e1a7004a171143a83163d6df460aaf61522695f207a58b95c0644d87e52aa1a347916e4f7a72930b1bc06dbe22ce3f58264afd23704cbb63b29b931f7de6c9d949a7ecfc", + }, + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA384, + msg = "sample", + k = "01546a108bc23a15d6f21872f7ded661fa8431ddbd922d0dcdb77cc878c8553ffad064c95a920a750ac9137e527390d2d92f153e66196966ea554d9adfcb109c4211", + sig = "01ea842a0e17d2de4f92c15315c63ddf72685c18195c2bb95e572b9c5136ca4b4b576ad712a52be9730627d16054ba40cc0b8d3ff035b12ae75168397f5d50c6745101f21a3cee066e1961025fb048bd5fe2b7924d0cd797babe0a83b66f1e35eeaf5fde143fa85dc394a7dee766523393784484bdf3e00114a1c857cde1aa203db65d61", + }, + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA512, + msg = "sample", + k = "01dae2ea071f8110dc26882d4d5eae0621a3256fc8847fb9022e2b7d28e6f10198b1574fdd03a9053c08a1854a168aa5a57470ec97dd5ce090124ef52a2f7ecbffd3", + sig = "00c328fafcbd79dd77850370c46325d987cb525569fb63c5d3bc53950e6d4c5f174e25a1ee9017b5d450606add152b534931d7d4e8455cc91f9b15bf05ec36e377fa00617cce7cf5064806c467f678d3b4080d6f1cc50af26ca209417308281b68af282623eaa63e5b5c0723d8b8c37ff0777b1a20f8ccb1dccc43997f1ee0e44da4a67a", + }, + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA1, + msg = "test", + k = "00bb9f2bf4fe1038ccf4dabd7139a56f6fd8bb1386561bd3c6a4fc818b20df5ddba80795a947107a1ab9d12daa615b1ade4f7a9dc05e8e6311150f47f5c57ce8b222", + sig = "013bad9f29abe20de37ebeb823c252ca0f63361284015a3bf430a46aaa80b87b0693f0694bd88afe4e661fc33b094cd3b7963bed5a727ed8bd6a3a202abe009d036701e9bb81ff7944ca409ad138dbbee228e1afcc0c890fc78ec8604639cb0dbdc90f717a99ead9d272855d00162ee9527567dd6a92cbd629805c0445282bbc916797ff", + }, + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA256, + msg = "test", + k = "001de74955efaabc4c4f17f8e84d881d1310b5392d7700275f82f145c61e843841af09035bf7a6210f5a431a6a9e81c9323354a9e69135d44ebd2fcaa7731b909258", + sig = "000e871c4a14f993c6c7369501900c4bc1e9c7b0b4ba44e04868b30b41d8071042eb28c4c250411d0ce08cd197e4188ea4876f279f90b3d8d74a3c76e6f1e4656aa800cd52dbaa33b063c3a6cd8058a1fb0a46a4754b034fcc644766ca14da8ca5ca9fde00e88c1ad60ccba759025299079d7a427ec3cc5b619bfbc828e7769bcd694e86", + }, + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA384, + msg = "test", + k = "01f1fc4a349a7da9a9e116bfdd055dc08e78252ff8e23ac276ac88b1770ae0b5dceb1ed14a4916b769a523ce1e90ba22846af11df8b300c38818f713dadd85de0c88", + sig = "014bee21a18b6d8b3c93fab08d43e739707953244fdbe924fa926d76669e7ac8c89df62ed8975c2d8397a65a49dcc09f6b0ac62272741924d479354d74ff6075578c0133330865c067a0eaf72362a65e2d7bc4e461e8c8995c3b6226a21bd1aa78f0ed94fe536a0dca35534f0cd1510c41525d163fe9d74d134881e35141ed5e8e95b979", + }, + testcase { + curve = tcurveid::P521, + qpoint = p521q, + x = p521x, + hashf = hashf::SHA512, + msg = "test", + k = "016200813020ec986863bedfc1b121f605c1215645018aea1a7b215a564de9eb1b38a67aa1128b80ce391c4fb71187654aaa3431027bfc7f395766ca988c964dc56d", + sig = "013e99020abf5cee7525d16b69b229652ab6bdf2affcaef38773b4b7d08725f10cdb93482fdcc54edcee91eca4166b2a7c6265ef0ce2bd7051b7cef945babd47ee6d01fbd0013c674aa79cb39849527916ce301c66ea7ce8b80682786ad60f98f7e78a19ca69eff5c57400e3b3a0ad66ce0978214d13baf4e9ac60752f7b155e2de4dce3", + }, +]); + +@test fn ecdsa_rfc6979() void = { + test::require("slow"); + + let sigbuf: [MAX_SIGSZ]u8 = [0...]; + let sumbuf: [sha512::SZ]u8 = [0...]; + let hashbuf: [sha512::SZ * 2 + sha512::BLOCKSZ]u8 = [0...]; + let cases = rfc6979_cases(); + defer free(cases); + + for (let tc &.. cases) { + let h: *hash::hash = switch (tc.hashf) { + case hashf::SHA1 => + yield &sha1::sha1(); + case hashf::SHA224 => + abort("not implemented"); + case hashf::SHA256 => + yield &sha256::sha256(); + case hashf::SHA384 => + yield &sha512::sha384(); + case hashf::SHA512 => + yield &sha512::sha512(); + case => + abort(); + }; + + let pub: *pubkey = switch (tc.curve) { + case tcurveid::P256 => + yield &p256pub(); + case tcurveid::P384 => + yield &p384pub(); + case tcurveid::P521 => + yield &p521pub(); + case => + abort(); + }; + + pubkey_buf(pub)[..] = tc.qpoint[..]; + + let sum = sumbuf[..hash::sz(h)]; + io::writeall(h, strings::toutf8(tc.msg))!; + hash::sum(h, sum); + + let sig = hex::decodestr(tc.sig)!; + defer free(sig); + + sigbuf[..len(sig)] = sig[..]; + + assert(verify(pub, sum, sigbuf[..len(sig)]) == 1); + let priv: *privkey = switch (tc.curve) { + case tcurveid::P256 => + yield &p256priv(); + case tcurveid::P384 => + yield &p384priv(); + case tcurveid::P521 => + yield &p521priv(); + case => + abort(); + }; + + privkey_buf(priv)[..] = tc.x[..]; + + const n = sign(priv, sum, h, hashbuf, sigbuf); + assert(n == sigsz(pub)); + assert(bytes::equal(sigbuf[..n], sig)); + }; +};