From 40803581d856db76db93e92f7b397af0f862bfad Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 20 Jun 2024 18:05:36 +0200 Subject: [PATCH] Test vectors reader/writer --- Cargo.toml | 1 + ... => bandersnatch_sha512_ell2_vectors.json} | 78 ++++++------ data/secp256_sha256_tai_vectors.json | 80 +++++++++++++ data/secp256_sha256_tai_vectors_rfc_9381.json | 41 +++++++ src/ietf.rs | 113 +++++------------- src/suites/bandersnatch.rs | 42 +------ src/suites/secp256.rs | 90 +++++++------- src/testing.rs | 64 ++++++++++ 8 files changed, 300 insertions(+), 209 deletions(-) rename data/{bandersnatch_vectors.json => bandersnatch_sha512_ell2_vectors.json} (88%) create mode 100644 data/secp256_sha256_tai_vectors.json create mode 100644 data/secp256_sha256_tai_vectors_rfc_9381.json diff --git a/Cargo.toml b/Cargo.toml index 03a61e0..a0fb5aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ ark-ed25519 = "0.4" hex = "0.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +indexmap = { version = "2.2.6", features = ["serde"] } [features] default = [ "std" ] diff --git a/data/bandersnatch_vectors.json b/data/bandersnatch_sha512_ell2_vectors.json similarity index 88% rename from data/bandersnatch_vectors.json rename to data/bandersnatch_sha512_ell2_vectors.json index f7ad067..35fa01f 100644 --- a/data/bandersnatch_vectors.json +++ b/data/bandersnatch_sha512_ell2_vectors.json @@ -1,74 +1,80 @@ [ { - "ad": "", + "comment": "bandersnatch-sha512-ell2-ed vector-0", + "sk": "2bd8776e6ca6a43d51987f756be88b643ab4431b523132f675c8f0004f5d5a17", + "pk": "76adde367eebc8b21f7ef37e327243a77e34e30f9a211fda05409b49f16f3473", "alpha": "", - "beta": "bfe3cce020f4ed87b86ca5e855b24f731256d72ef741fa28021a85c90785207b9bcb07a8d763133b7bc07ca1a1ddece2033cf1ba3016678f9287ffe7dec0aec1", - "flags": "00", - "gamma": "4168f6407d5caccbe46820af3d032ff88952b824643acd1688cbef176e30572e", + "ad": "", "h": "839b7fb1019a640e6d7a2d6b20f3ec38ceb91ffc72cf3b86866cc659d95d39c1", - "pk": "76adde367eebc8b21f7ef37e327243a77e34e30f9a211fda05409b49f16f3473", + "gamma": "4168f6407d5caccbe46820af3d032ff88952b824643acd1688cbef176e30572e", + "beta": "bfe3cce020f4ed87b86ca5e855b24f731256d72ef741fa28021a85c90785207b9bcb07a8d763133b7bc07ca1a1ddece2033cf1ba3016678f9287ffe7dec0aec1", "proof_c": "bb7f81b613a2fbf6ff8af9c0118f0459e52b85fe0538b5a5fe54958681ac2303", "proof_s": "2817d61674ce9e87a56c836504c1179bcb502091e32290840455e37e88d0ba05", - "sk": "2bd8776e6ca6a43d51987f756be88b643ab4431b523132f675c8f0004f5d5a17" + "flags": "00" }, { - "ad": "", + "comment": "bandersnatch-sha512-ell2-ed vector-1", + "sk": "3d6406500d4009fdf2604546093665911e753f2213570a29521fd88bc30ede18", + "pk": "a1b1da71cc4682e159b7da23050d8b6261eb11a3247c89b07ef56ccd002fd38b", "alpha": "0a", - "beta": "86bb79d0600666564499071115fda4a0a775516b0fcd7a418c50224bc05e4436039327c35a9ffc7ba37d79403007330cfa28b67c924a3b4779cc8afc3f08047c", - "flags": "00", - "gamma": "059d738d0721dc7f1509b43d58959b127d2d09ed3696e5c8bd734cb608dc51e1", + "ad": "", "h": "df672c03b4cc0480a3fcb7951b2707d40fad72ade6e79870e4e0cee6ea16d1d3", - "pk": "a1b1da71cc4682e159b7da23050d8b6261eb11a3247c89b07ef56ccd002fd38b", + "gamma": "059d738d0721dc7f1509b43d58959b127d2d09ed3696e5c8bd734cb608dc51e1", + "beta": "86bb79d0600666564499071115fda4a0a775516b0fcd7a418c50224bc05e4436039327c35a9ffc7ba37d79403007330cfa28b67c924a3b4779cc8afc3f08047c", "proof_c": "7c0949571bd9231172592bfc85d262727f0a4737334f0daace4991adfb86fd03", "proof_s": "b4d492d97a2283e56e403e650bc30031fec3ff888f35816a6ebbfc9121fab11b", - "sk": "3d6406500d4009fdf2604546093665911e753f2213570a29521fd88bc30ede18" + "flags": "00" }, { - "ad": "0b8c", + "comment": "bandersnatch-sha512-ell2-ed vector-2", + "sk": "8b9063872331dda4c3c282f7d813fb3c13e7339b7dc9635fdc764e32cc57cb15", + "pk": "5ebfe047f421e1a3e1d9bbb163839812657bbb3e4ffe9856a725b2b405844cf3", "alpha": "", - "beta": "7c263cc2a83841440fa85f4d352832d97f5d1b54a684df6efc3cd1743cc7d59f40d282271e900b8e4fba693be1b6b46e9544e64fed628984b257cb0557b0d8d5", - "flags": "00", - "gamma": "eb2d6a9a60b3acc1258ed35d815aaf6932fe76388fae3dbfc9594d5bee09c73f", + "ad": "0b8c", "h": "48adf7aec95508704959f279dc00a3430c8fb55f39d0d7598f4d02ef51abaabc", - "pk": "5ebfe047f421e1a3e1d9bbb163839812657bbb3e4ffe9856a725b2b405844cf3", + "gamma": "eb2d6a9a60b3acc1258ed35d815aaf6932fe76388fae3dbfc9594d5bee09c73f", + "beta": "7c263cc2a83841440fa85f4d352832d97f5d1b54a684df6efc3cd1743cc7d59f40d282271e900b8e4fba693be1b6b46e9544e64fed628984b257cb0557b0d8d5", "proof_c": "55ea5766affceb74132d413f40bd35b45b7fe803bb08fda041fffd2a98bbe008", "proof_s": "55f2199be6174666e2bd3d7f1b731e48cc3267f934460fd598c15f045c04da01", - "sk": "8b9063872331dda4c3c282f7d813fb3c13e7339b7dc9635fdc764e32cc57cb15" + "flags": "00" }, { - "ad": "", + "comment": "bandersnatch-sha512-ell2-ed vector-3", + "sk": "6db187202f69e627e432296ae1d0f166ae6ac3c1222585b6ceae80ea07670b14", + "pk": "9d97151298a5339866ddd3539d16696e19e6b68ac731562c807fe63a1ca49506", "alpha": "73616d706c65", - "beta": "df36d83a3d0a0e07def33b2be7bf2872bcc0cdb9fabe069a4d124ee062369450198c56526711aacc5994040e0d67bebd2a4e7f1968e38fc5f19e1cfda3dbe850", - "flags": "00", - "gamma": "779f7e5e173d34ce011edf8f009396fd1164466d37dfdf983af41b421bc0c1e5", + "ad": "", "h": "ae61160b30625ec0b35a7bdfcdecae3da89fb3ca0fce295d38e435e7ec71ba21", - "pk": "9d97151298a5339866ddd3539d16696e19e6b68ac731562c807fe63a1ca49506", + "gamma": "779f7e5e173d34ce011edf8f009396fd1164466d37dfdf983af41b421bc0c1e5", + "beta": "df36d83a3d0a0e07def33b2be7bf2872bcc0cdb9fabe069a4d124ee062369450198c56526711aacc5994040e0d67bebd2a4e7f1968e38fc5f19e1cfda3dbe850", "proof_c": "79cea3ed5c701f2cd5694934263320c614e5b0f0e64a16ff805f48e7cc520e1b", "proof_s": "7c7f25be26291ed5ab59af6ae3be049fb699d849f712276eacb98fa4d45a4515", - "sk": "6db187202f69e627e432296ae1d0f166ae6ac3c1222585b6ceae80ea07670b14" + "flags": "00" }, { - "ad": "", + "comment": "bandersnatch-sha512-ell2-ed vector-4", + "sk": "b56cc204f1b6c2323709012cb16c72f3021035ce935fbe69b600a88d842c7407", + "pk": "dc2de7312c2850a9f6c103289c64fbd76e2ebd2fa8b5734708eb2c76c0fb2d99", "alpha": "42616e646572736e6174636820766563746f72", - "beta": "b0992cf128b1d611d1e4b5fe12bd3c502513d2db938afc701ccb4f29da4a283ec824e267c3cce7c62c689337ffca45ef377fd23d106a8fff18f81860502ad819", - "flags": "00", - "gamma": "1c7ed6a09bc8d5a4b350e0071e0b78013179d7539655304f4b73390dc3586b51", + "ad": "", "h": "fa9d66cf9f5ba4c78e223ead5dca3a1bef508a281c6053af23148c37d9c20464", - "pk": "dc2de7312c2850a9f6c103289c64fbd76e2ebd2fa8b5734708eb2c76c0fb2d99", + "gamma": "1c7ed6a09bc8d5a4b350e0071e0b78013179d7539655304f4b73390dc3586b51", + "beta": "b0992cf128b1d611d1e4b5fe12bd3c502513d2db938afc701ccb4f29da4a283ec824e267c3cce7c62c689337ffca45ef377fd23d106a8fff18f81860502ad819", "proof_c": "7b58ff009e6457ea41c2562cee63200b69103af58a548841660fc73954c59a04", "proof_s": "6cb5f5f92b6fb10f3370fbfb5a62bdb618185bdd345dd22320690b7c8269ba05", - "sk": "b56cc204f1b6c2323709012cb16c72f3021035ce935fbe69b600a88d842c7407" + "flags": "00" }, { - "ad": "73616d706c65", + "comment": "bandersnatch-sha512-ell2-ed vector-5", + "sk": "da36359bf1bfd1694d3ed359e7340bd02a6a5e54827d94db1384df29f5bdd302", + "pk": "decb0151cbeb49f76f10419ab6a96242bdc87baac8a474e5161123de4304ac29", "alpha": "42616e646572736e6174636820766563746f72", - "beta": "ad227f825b97de4538b70438f5915f0bf4a597dfb34404700c2cbcc29983fdb594058b30df691e0b89d500b5ed1d449c335be4405a8c5e4c025e63f68acd86c2", - "flags": "00", - "gamma": "25c46b117dcfeceb2debbb14fd976e403eff1cf6f6f945f53cbeb49e7e214925", + "ad": "73616d706c65", "h": "9fd95dfca41d55e20ca783c4792ae8d35f20b56b4113945a1f3e411e733bc99a", - "pk": "decb0151cbeb49f76f10419ab6a96242bdc87baac8a474e5161123de4304ac29", + "gamma": "25c46b117dcfeceb2debbb14fd976e403eff1cf6f6f945f53cbeb49e7e214925", + "beta": "ad227f825b97de4538b70438f5915f0bf4a597dfb34404700c2cbcc29983fdb594058b30df691e0b89d500b5ed1d449c335be4405a8c5e4c025e63f68acd86c2", "proof_c": "f1aa703dbd38cb28586d42dd671b1967153e3410308b7f97dfcdfa00f0fd1919", "proof_s": "3e26dd7e5cbc1f8b5d38ad8c39085446aee4acf76ce57e5f8eca1d38fc30af10", - "sk": "da36359bf1bfd1694d3ed359e7340bd02a6a5e54827d94db1384df29f5bdd302" + "flags": "00" } ] \ No newline at end of file diff --git a/data/secp256_sha256_tai_vectors.json b/data/secp256_sha256_tai_vectors.json new file mode 100644 index 0000000..c6e2e98 --- /dev/null +++ b/data/secp256_sha256_tai_vectors.json @@ -0,0 +1,80 @@ +[ + { + "comment": "secp256r1_sha256_tai vector-0", + "sk": "1da0af1706a31185763837b33f1d90782c0a78bbe644a59c987ab3ff9c0b346e", + "pk": "0279c7e97a3a7fd19265b046236c4216c19cc9a9e0f16b890295cffb5a1cc990f1", + "alpha": "", + "ad": "", + "h": "02ce0d7db4edd23b99b3736443c53ad12b133266c45646be3902a854606672e6ef", + "gamma": "0298b844148e41d128a2f2d49eb208618039cd9ece62d0fc2659461ebe2c7df2ac", + "beta": "92fd1eff9ddb4173ee87c45476b1c43486da7c20efd7a3c5b88891cf99bcd680", + "proof_c": "000000000000000000000000000000007b331610072248bd15c7aef0832ae2f9", + "proof_s": "d30c63494b5e087f26bca7e3b57dd4876f6d01597e9ac272f33c7ac48f11a5b8", + "flags": "00" + }, + { + "comment": "secp256r1_sha256_tai vector-1", + "sk": "9a4585773ce2ccd7a585c331d60a60d1e3b7d28cbb2ede3bc55445342f12f54b", + "pk": "0218e11f9ef92fa3929aa8f078d2e73b58f0ac7d6f274e222b8515c7b0140138be", + "alpha": "0a", + "ad": "", + "h": "0242336b14ccf0f101b64a1cca4b08f72f6be851f717dc56c07262500a84071e06", + "gamma": "03b2ae579ccf850038d9ba6b94a87646e8ecdec789639aab4c1492f11b114e6515", + "beta": "f30b3d4fb257c287cf423d044796ce1eaf6ec9c9d42ae4305274dad9a2fbd4dd", + "proof_c": "00000000000000000000000000000000230bcb8e6ff67f15e2aa27a7e570e743", + "proof_s": "8fdd6585e6ca4e09ada872c09c2ccacaa60df0cd919b10c4e2a68285ba236105", + "flags": "00" + }, + { + "comment": "secp256r1_sha256_tai vector-2", + "sk": "86d9576498ea764b49243efeb05df625010438c6a55d5b578de4ff00c9b4c1db", + "pk": "03a47366bc18483e02261117304cdf77cc95f234c16d11a8356dc4514a7adaf120", + "alpha": "", + "ad": "0b8c", + "h": "03b90c05c10ddbfdafda6a964012946641737f888b90c930abdd2454c568f73d70", + "gamma": "03c572767b190538c104182dfac985cd58430074f0db24305f4006d896c93b96c7", + "beta": "d06d1139d2f0199b36d48b8d4980421e3d98504442e475c1760dcbbd19d27543", + "proof_c": "000000000000000000000000000000004b5b11f3b418095a5d02f835a283cc99", + "proof_s": "78bd588629d7dbfa7909384fc55590443f7d72996655ca933bf5979ccf342e14", + "flags": "00" + }, + { + "comment": "secp256r1_sha256_tai vector-3", + "sk": "c529ffad9a5ab61162b11d616b639e00586ba846746a197d4daf78b908ed4f08", + "pk": "02d984ff7d61ba3a11d8ade6cea6ba949fba3bbcf841506cf8c3a7b6e1bd67b926", + "alpha": "73616d706c65", + "ad": "", + "h": "02bca955248372984158e0f9bf7d8d9bb1ee87f188cf27e93647a967a0f9b09535", + "gamma": "0323c860bdba4ceccc28ebed9283dc6f74b4e16c94ffe566f49318b955458c20e3", + "beta": "cd9444669432a6b5ca8ad3a4adcd8152fb8a76e327877ea876e6bf3e761b6e13", + "proof_c": "00000000000000000000000000000000c209c08df735f0a15e6318fcb7158693", + "proof_s": "9db4909d8cab16e9e79004fc74fc66eb3560debbad9aaa01f61e4077f893f1f7", + "flags": "00" + }, + { + "comment": "secp256r1_sha256_tai vector-4", + "sk": "719ec881a39ca062f09262ff75fc8a06d6cb91ad078c4d344723508c509c2de5", + "pk": "02c8f77b17ec60330366b9e148dfa565a7c8d6a0768e5737786722e3c85a5ff054", + "alpha": "42616e646572736e6174636820766563746f72", + "ad": "", + "h": "039edace829d35ef117e135c8b81b5b00a0d3c9f24a349761fc07a7503bf048966", + "gamma": "02d7b9b206af6fae3a6225ef09701e965e5387a22eca8e1bc71c167cd53f66903a", + "beta": "0f4965be7ec48d075a0035d5d1874a05328cb9f1cbe6b4066813ebb38e46b101", + "proof_c": "00000000000000000000000000000000ebc773f07f5a559bf176f57f83d5d80d", + "proof_s": "e0f386d45474ea6eb40ebf59e4c7e6695813b6bf4b7984db868e415d1d3432e9", + "flags": "00" + }, + { + "comment": "secp256r1_sha256_tai vector-5", + "sk": "db43b75a9c05eb89ae926b7b1d5081e79def64a210f5b6bd0d0be3e99a9a7be7", + "pk": "03c443ab7bbb42585044551b7efac1d9c3c8f007bdf0c325d35fde5417bbb8e11d", + "alpha": "42616e646572736e6174636820766563746f72", + "ad": "73616d706c65", + "h": "029d367ea8eaf47bdb453f836c0c6afe9e5540c33adf4b20e1ecdf96c45f07ed1f", + "gamma": "0288734131a4dddb3a69e0ff346bd6afa5fcf29a328f1a4f7fa00c512127960e33", + "beta": "0a53ce69bc69cf00fc7f42a74717d8271fb6f7124351697e64e006e1e77733ba", + "proof_c": "000000000000000000000000000000007a1041d32a0e043ab11822977b6108b9", + "proof_s": "b46c510a1bd8605aaf76d61407ea94a1158244b9b513a1653dfd347e2ea33847", + "flags": "00" + } +] \ No newline at end of file diff --git a/data/secp256_sha256_tai_vectors_rfc_9381.json b/data/secp256_sha256_tai_vectors_rfc_9381.json new file mode 100644 index 0000000..696c9ae --- /dev/null +++ b/data/secp256_sha256_tai_vectors_rfc_9381.json @@ -0,0 +1,41 @@ +[ + { + "comment": "secp256r1_sha256_tai - rfc-9381-vector-10 (Spec typos: gamma, h. Skip proof)", + "sk": "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "pk": "0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6", + "alpha": "73616D706C65", + "ad": "", + "h": "0372a877532e9ac193aff4401234266f59900a4a9e3fc3cfc6a4b7e467a15d06d4", + "gamma": "025b5c726e8c0e2c488a107c600578ee75cb702343c153cb1eb8dec77f4b5071b4", + "beta": "a3ad7b0ef73d8fc6655053ea22f9bede8c743f08bbed3d38821f0e16474b505e", + "proof_c": "", + "proof_s": "", + "flags": "01" + }, + { + "comment": "secp256r1_sha256_tai - rfc-9381-vector-11", + "sk": "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "pk": "0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6", + "alpha": "74657374", + "ad": "", + "h": "02173119b4fff5e6f8afed4868a29fe8920f1b54c2cf89cc7b301d0d473de6b974", + "gamma": "034dac60aba508ba0c01aa9be80377ebd7562c4a52d74722e0abae7dc3080ddb56", + "beta": "a284f94ceec2ff4b3794629da7cbafa49121972671b466cab4ce170aa365f26d", + "proof_c": "00000000000000000000000000000000c19e067b15a8a8174905b13617804534", + "proof_s": "214f935b94c2287f797e393eb0816969d864f37625b443f30f1a5a33f2b3c854", + "flags": "00" + }, + { + "comment": "secp256r1_sha256_tai - rfc-9381-vector-12", + "sk": "2ca1411a41b17b24cc8c3b089cfd033f1920202a6c0de8abb97df1498d50d2c8", + "pk": "03596375e6ce57e0f20294fc46bdfcfd19a39f8161b58695b3ec5b3d16427c274d", + "alpha": "4578616D706C65207573696E67204543445341206B65792066726F6D20417070656E646978204C2E342E32206F6620414E53492E58392D36322D32303035", + "ad": "", + "h": "0258055c26c4b01d01c00fb57567955f7d39cd6f6e85fd37c58f696cc6b7aa761d", + "gamma": "03d03398bf53aa23831d7d1b2937e005fb0062cbefa06796579f2a1fc7e7b8c667", + "beta": "90871e06da5caa39a3c61578ebb844de8635e27ac0b13e829997d0d95dd98c19", + "proof_c": "00000000000000000000000000000000d091c00b0f5c3619d10ecea44363b5a5", + "proof_s": "99cadc5b2957e223fec62e81f7b4825fc799a771a3d7334b9186bdbee87316b1", + "flags": "00" + } +] diff --git a/src/ietf.rs b/src/ietf.rs index b62c730..62d1aee 100644 --- a/src/ietf.rs +++ b/src/ietf.rs @@ -132,7 +132,8 @@ pub mod testing { pub const TEST_FLAG_SKIP_PROOF_CHECK: u8 = 1 << 0; - pub struct TestVector2 { + pub struct TestVector { + pub comment: String, pub sk: ScalarField, pub pk: AffinePoint, pub alpha: Vec, @@ -145,8 +146,15 @@ pub mod testing { pub flags: u8, } - impl TestVector2 { - pub fn new(seed: &[u8], alpha: &[u8], salt: Option<&[u8]>, ad: &[u8], flags: u8) -> Self { + impl TestVector { + pub fn new( + comment: &str, + seed: &[u8], + alpha: &[u8], + salt: Option<&[u8]>, + ad: &[u8], + flags: u8, + ) -> Self { let sk = Secret::::from_seed(seed); let pk = sk.public().0; @@ -165,7 +173,8 @@ pub mod testing { let proof = sk.prove(input, output, ad); - TestVector2 { + TestVector { + comment: comment.to_string(), sk: sk.scalar, pk, alpha, @@ -180,6 +189,8 @@ pub mod testing { } pub fn run(&self) { + println!("Running test vector: {}", self.comment); + let sk = Secret::::from_scalar(self.sk); let pk = sk.public(); @@ -197,13 +208,13 @@ pub mod testing { let output = sk.output(input); assert_eq!(self.gamma, output.0, "VRF pre-output ('gamma') mismatch"); - let beta = output.hash().to_vec(); - assert_eq!(self.beta, beta, "VRF output ('beta') mismatch"); - if self.flags & TEST_FLAG_SKIP_PROOF_CHECK != 0 { return; } + let beta = output.hash().to_vec(); + assert_eq!(self.beta, beta, "VRF output ('beta') mismatch"); + let proof = sk.prove(input, output, &self.ad); assert_eq!(self.c, proof.c, "VRF proof challenge ('c') mismatch"); assert_eq!(self.s, proof.s, "VRF proof response ('s') mismatch"); @@ -212,7 +223,7 @@ pub mod testing { } } - impl core::fmt::Debug for TestVector2 { + impl core::fmt::Debug for TestVector { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let sk = hex::encode(utils::encode_scalar::(&self.sk)); let pk = hex::encode(utils::encode_point::(&self.pk)); @@ -224,6 +235,7 @@ pub mod testing { let c = hex::encode(utils::encode_scalar::(&self.c)); let s = hex::encode(utils::encode_scalar::(&self.s)); f.debug_struct("TestVector") + .field("comment", &self.comment) .field("sk", &sk) .field("pk", &pk) .field("alpha", &alpha) @@ -239,11 +251,12 @@ pub mod testing { } #[derive(Debug, serde::Serialize, serde::Deserialize)] - pub struct TestVectorMap(std::collections::BTreeMap); + pub struct TestVectorMap(indexmap::IndexMap); - impl From> for TestVectorMap { - fn from(v: TestVector2) -> Self { + impl From> for TestVectorMap { + fn from(v: TestVector) -> Self { let items = [ + ("comment", v.comment), ("sk", hex::encode(utils::encode_scalar::(&v.sk))), ("pk", hex::encode(utils::encode_point::(&v.pk))), ("alpha", hex::encode(&v.alpha)), @@ -255,15 +268,16 @@ pub mod testing { ("proof_s", hex::encode(utils::encode_scalar::(&v.s))), ("flags", hex::encode(&[v.flags])), ]; - let map: std::collections::BTreeMap = + let map: indexmap::IndexMap = items.into_iter().map(|(k, v)| (k.to_string(), v)).collect(); Self(map) } } - impl From for TestVector2 { + impl From for TestVector { fn from(map: TestVectorMap) -> Self { let item_bytes = |field| hex::decode(map.0.get(field).unwrap()).unwrap(); + let comment = map.0.get("comment").unwrap().to_string(); let sk = utils::decode_scalar::(&item_bytes("sk")); let pk = utils::decode_point::(&item_bytes("pk")); let alpha = item_bytes("alpha"); @@ -274,8 +288,8 @@ pub mod testing { let c = utils::decode_scalar::(&item_bytes("proof_c")); let s = utils::decode_scalar::(&item_bytes("proof_s")); let flags = item_bytes("flags")[0]; - Self { + comment, sk, pk, alpha, @@ -289,77 +303,6 @@ pub mod testing { } } } - - pub struct TestVector { - pub flags: u8, - /// Secret key - pub sk: &'static str, - /// Public key - pub pk: &'static str, - /// VRF input string - pub alpha: &'static [u8], - /// VRF output hash - pub beta: &'static str, - /// Hash to curve (salt||alpha), salt=encode(pk) - pub h: &'static str, - pub gamma: &'static str, - pub c: &'static str, - pub s: &'static str, - pub ad: &'static str, - } - - pub fn run_test_vector(v: &TestVector) { - let ad = hex::decode(v.ad).unwrap(); - - let sk_bytes = hex::decode(v.sk).unwrap(); - let s = S::scalar_decode(&sk_bytes); - let sk = Secret::::from_scalar(s); - - let pk = sk.public(); - let pk_bytes = utils::encode_point::(&pk.0); - assert_eq!(v.pk, hex::encode(&pk_bytes), "public key ('pk') mismatch"); - - // Prepare hash_to_curve data = salt || alpha - // Salt is defined to be pk (adjust it to make the encoding to match) - let h2c_data = [&pk_bytes[..], v.alpha].concat(); - let h = S::data_to_point(&h2c_data).unwrap(); - let h_bytes = utils::encode_point::(&h); - assert_eq!(v.h, hex::encode(h_bytes), "hash-to-curve ('h') mismatch"); - - let input = Input::from(h); - let output = sk.output(input); - let proof = sk.prove(input, output, &ad); - - let gamma_bytes = utils::encode_point::(&output.0); - assert_eq!( - v.gamma, - hex::encode(gamma_bytes), - "VRF pre-output ('gamma') mismatch" - ); - - let beta = output.hash(); - assert_eq!(v.beta, hex::encode(beta), "VRF output ('beta') mismatch"); - - if v.flags & TEST_FLAG_SKIP_PROOF_CHECK != 0 { - return; - } - - let c_bytes = utils::encode_scalar::(&proof.c); - assert_eq!( - v.c, - hex::encode(c_bytes), - "VRF proof challenge ('c') mismatch" - ); - - let s_bytes = utils::encode_scalar::(&proof.s); - assert_eq!( - v.s, - hex::encode(s_bytes), - "VRF proof response ('s') mismatch" - ); - - assert!(pk.verify(input, output, &ad, &proof).is_ok()); - } } #[cfg(test)] diff --git a/src/suites/bandersnatch.rs b/src/suites/bandersnatch.rs index aed7731..a293e6b 100644 --- a/src/suites/bandersnatch.rs +++ b/src/suites/bandersnatch.rs @@ -245,56 +245,22 @@ mod tests { #[cfg(test)] mod test_vectors_edwards { use super::edwards::*; - use crate::ietf::testing::*; + use crate::testing; type S = BandersnatchSha512Ell2; const TEST_VECTORS_FILE: &str = concat!( env!("CARGO_MANIFEST_DIR"), - "/data/bandersnatch_vectors.json" + "/data/bandersnatch_sha512_ell2_vectors.json" ); #[test] fn test_vectors_process() { - use std::{fs::File, io::BufReader}; - - let file = File::open(TEST_VECTORS_FILE).unwrap(); - let reader = BufReader::new(file); - - let vector_maps: Vec = serde_json::from_reader(reader).unwrap(); - - for vector_map in vector_maps { - let vector = TestVector2::::from(vector_map); - vector.run(); - } + testing::test_vectors_process::(TEST_VECTORS_FILE); } #[test] fn test_vectors_generate() { - use std::{fs::File, io::Write}; - // ("alpha", "ad")) - let var_data: Vec<(&[u8], &[u8])> = vec![ - (b"", b""), - (b"0a", b""), - (b"", b"0b8c"), - (b"73616D706C65", b""), - (b"42616E646572736E6174636820766563746F72", b""), - (b"42616E646572736E6174636820766563746F72", b"73616D706C65"), - ]; - - let mut vector_maps = Vec::with_capacity(var_data.len()); - - for (i, var_data) in var_data.iter().enumerate() { - let alpha = hex::decode(var_data.0).unwrap(); - let ad = hex::decode(var_data.1).unwrap(); - let vector = TestVector2::::new(&[i as u8], &alpha, None, &ad, 0); - println!("{:#?}", vector); - vector.run(); - vector_maps.push(TestVectorMap::from(vector)); - } - - let mut file = File::create(TEST_VECTORS_FILE).unwrap(); - let json = serde_json::to_string_pretty(&vector_maps).unwrap(); - file.write_all(json.as_bytes()).unwrap(); + testing::test_vectors_generate::(TEST_VECTORS_FILE); } } diff --git a/src/suites/secp256.rs b/src/suites/secp256.rs index bd4b126..e9db78c 100644 --- a/src/suites/secp256.rs +++ b/src/suites/secp256.rs @@ -51,7 +51,7 @@ use crate::{pedersen::PedersenSuite, *}; use ark_ff::MontFp; -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct P256Sha256Tai; suite_types!(P256Sha256Tai); @@ -92,6 +92,27 @@ impl Suite for P256Sha256Tai { buf.extend_from_slice(&tmp[..]); } + /// Encode point according to Section 2.3.3 "SEC 1: Elliptic Curve Cryptography", + /// (https://www.secg.org/sec1-v2.pdf) with point compression on. + fn point_decode(buf: &[u8]) -> AffinePoint { + use ark_ff::biginteger::BigInteger; + if buf.len() == 1 && buf[0] == 0x00 { + return AffinePoint::zero(); + } + let mut tmp = buf.to_vec(); + tmp.reverse(); + let y_flag = tmp.pop().unwrap(); + + let x = BaseField::deserialize_compressed(&mut &tmp[..]).unwrap(); + let (y1, y2) = AffinePoint::get_ys_from_x_unchecked(x).unwrap(); + let y = if ((y_flag & 0x01) != 0) == y1.into_bigint().is_odd() { + y1 + } else { + y2 + }; + AffinePoint::new_unchecked(x, y) + } + fn scalar_encode(sc: &ScalarField, buf: &mut Vec) { let mut tmp = Vec::new(); sc.serialize_compressed(&mut tmp).unwrap(); @@ -119,62 +140,31 @@ impl PedersenSuite for P256Sha256Tai { #[cfg(test)] mod test_vectors { use super::*; - use crate::ietf::testing::*; - #[test] - fn rfc_9381_10() { - let v = TestVector { - flags: TEST_FLAG_SKIP_PROOF_CHECK, - sk: "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", - pk: "0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6", - alpha: b"sample", - beta: "a3ad7b0ef73d8fc6655053ea22f9bede8c743f08bbed3d38821f0e16474b505e", - // RFC sets sign byte to 0x02, but it is not correct as y is odd - h: "0372a877532e9ac193aff4401234266f59900a4a9e3fc3cfc6a4b7e467a15d06d4", - // RFC sets sign byte to 0x03, but it is not correct as y is even - gamma: "025b5c726e8c0e2c488a107c600578ee75cb702343c153cb1eb8dec77f4b5071b4", - // Skip these checks as test vector looks like is not correct - c: "", - s: "", - ad: "", - }; + type S = P256Sha256Tai; - run_test_vector::(&v); - } + const TEST_VECTORS_FILE: &str = concat!( + env!("CARGO_MANIFEST_DIR"), + "/data/secp256_sha256_tai_vectors.json" + ); - #[test] - fn rfc_9381_11() { - let v = TestVector { - flags: 0, - sk: "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", - pk: "0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6", - alpha: b"test", - beta: "a284f94ceec2ff4b3794629da7cbafa49121972671b466cab4ce170aa365f26d", - h: "02173119b4fff5e6f8afed4868a29fe8920f1b54c2cf89cc7b301d0d473de6b974", - gamma: "034dac60aba508ba0c01aa9be80377ebd7562c4a52d74722e0abae7dc3080ddb56", - c: "00000000000000000000000000000000c19e067b15a8a8174905b13617804534", - s: "214f935b94c2287f797e393eb0816969d864f37625b443f30f1a5a33f2b3c854", - ad: "", - }; + const TEST_VECTORS_FILE_RFC_9381: &str = concat!( + env!("CARGO_MANIFEST_DIR"), + "/data/secp256_sha256_tai_vectors_rfc_9381.json" + ); - run_test_vector::(&v); + #[test] + fn test_vectors_generate() { + testing::test_vectors_generate::(TEST_VECTORS_FILE); } #[test] - fn rfc_9381_12() { - let v = TestVector { - flags: 0, - sk: "2ca1411a41b17b24cc8c3b089cfd033f1920202a6c0de8abb97df1498d50d2c8", - pk: "03596375e6ce57e0f20294fc46bdfcfd19a39f8161b58695b3ec5b3d16427c274d", - alpha: b"Example using ECDSA key from Appendix L.4.2 of ANSI.X9-62-2005", - beta: "90871e06da5caa39a3c61578ebb844de8635e27ac0b13e829997d0d95dd98c19", - h: "0258055c26c4b01d01c00fb57567955f7d39cd6f6e85fd37c58f696cc6b7aa761d", - gamma: "03d03398bf53aa23831d7d1b2937e005fb0062cbefa06796579f2a1fc7e7b8c667", - c: "00000000000000000000000000000000d091c00b0f5c3619d10ecea44363b5a5", - s: "99cadc5b2957e223fec62e81f7b4825fc799a771a3d7334b9186bdbee87316b1", - ad: "", - }; + fn test_vectors_process() { + testing::test_vectors_process::(TEST_VECTORS_FILE); + } - run_test_vector::(&v); + #[test] + fn test_vectors_process_rfc_9381() { + testing::test_vectors_process::(TEST_VECTORS_FILE_RFC_9381); } } diff --git a/src/testing.rs b/src/testing.rs index 988ce90..c83cae0 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -149,3 +149,67 @@ macro_rules! ring_suite_tests { }; ($suite:ident, false) => {}; } + +use ietf::testing::{TestVector, TestVectorMap}; + +fn vec_to_ascii_string(buf: &[u8]) -> Option { + if buf.iter().all(|&c| c.is_ascii_graphic() || c == b' ') { + Some(String::from_utf8(buf.to_vec()).unwrap()) + } else { + None + } +} + +// Some aliases for built-in suites without a printable SUITE-ID +pub fn suite_alias(id: &[u8]) -> Option { + let alias_map: std::collections::BTreeMap<&[u8], &str> = + vec![(&[0x01_u8][..], "secp256r1_sha256_tai")] + .into_iter() + .collect(); + alias_map.get(id).map(|s| s.to_string()) +} + +pub fn test_vectors_generate(file: &str) { + use std::{fs::File, io::Write}; + // ("alpha", "ad")) + let var_data: Vec<(&[u8], &[u8])> = vec![ + (b"", b""), + (b"0a", b""), + (b"", b"0b8c"), + (b"73616D706C65", b""), + (b"42616E646572736E6174636820766563746F72", b""), + (b"42616E646572736E6174636820766563746F72", b"73616D706C65"), + ]; + + let mut vector_maps = Vec::with_capacity(var_data.len()); + + for (i, var_data) in var_data.iter().enumerate() { + let alpha = hex::decode(var_data.0).unwrap(); + let ad = hex::decode(var_data.1).unwrap(); + let suite_string = + vec_to_ascii_string(S::SUITE_ID).unwrap_or_else(|| suite_alias(S::SUITE_ID).unwrap()); + let comment = format!("{} vector-{}", suite_string, i); + let vector = TestVector::::new(&comment, &[i as u8], &alpha, None, &ad, 0); + println!("{:#?}", vector); + vector.run(); + vector_maps.push(TestVectorMap::from(vector)); + } + + let mut file = File::create(file).unwrap(); + let json = serde_json::to_string_pretty(&vector_maps).unwrap(); + file.write_all(json.as_bytes()).unwrap(); +} + +pub fn test_vectors_process(file: &str) { + use std::{fs::File, io::BufReader}; + + let file = File::open(file).unwrap(); + let reader = BufReader::new(file); + + let vector_maps: Vec = serde_json::from_reader(reader).unwrap(); + + for vector_map in vector_maps { + let vector = TestVector::::from(vector_map); + vector.run(); + } +}