diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 923dc2c..2121e70 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -9,9 +9,7 @@ jobs: runs-on: macos-latest strategy: matrix: - # MSRV 1.47 temporarily removed - # See https://github.com/Argyle-Software/kyber/issues/34 - rust: [stable] + rust: [1.56.0, stable] # MSRV 1.56 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/cross.yml b/.github/workflows/cross.yml index c42114e..6d97df9 100644 --- a/.github/workflows/cross.yml +++ b/.github/workflows/cross.yml @@ -12,22 +12,13 @@ jobs: aarch64-linux-android, aarch64-unknown-linux-gnu, aarch64-unknown-linux-musl, - arm-linux-androideabi, arm-unknown-linux-gnueabi, armv7-unknown-linux-gnueabihf, mips-unknown-linux-gnu, mips64-unknown-linux-gnuabi64, - # powerpc-unknown-linux-gnu, - # powerpc64-unknown-linux-gnu, - # riscv64gc-unknown-linux-gnu, - # s390x-unknown-linux-gnu, - # x86_64-unknown-freebsd, - # x86_64-unknown-illumos, - # x86_64-unknown-linux-musl, - # x86_64-unknown-netbsd, ] feature: [kyber512, kyber768, kyber1024] - opt: ["", 90s] + opt: ["", 90s, "90s-fixslice"] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 210c586..e285afa 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -13,8 +13,7 @@ jobs: strategy: matrix: target: [i686-unknown-linux-gnu, x86_64-unknown-linux-gnu] - # MSRV 1.47 - rust: [1.47.0, stable] + rust: [1.56.0, stable] # MSRV 1.56 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 705f21d..96c081d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -16,7 +16,7 @@ jobs: aarch64-pc-windows-msvc ] - rust: [1.47.0, stable] # MSRV 1.47 + rust: [1.56.0, stable] # MSRV 1.56 steps: - uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index f84c3f3..4b48dd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,10 @@ rand_core = { version = "0.6.4", default-features = false } wasm-bindgen = { version = "0.2.83", optional = true } sha2 = { version = "0.10.6", optional = true , default-features = false } getrandom = {version = "0.2.8", features = ["js"], optional = true } -zeroize = { version = "1.5.7", features = ["derive"], optional = true } +zeroize = { version = "1.5.7", optional = true } +aes = { version = "0.8.2", optional = true } +ctr = { version = "0.9.2", optional = true } +pqc_core = { version = "0.2.0", features = ["zero"]} # Optional dev-deps, see https://github.com/rust-lang/cargo/issues/1596 criterion = { version = "0.4.0", features = ["html_reports"], optional = true } @@ -54,11 +57,16 @@ kyber1024 = [] hazmat = [] ### Additional features ### -# 90s mode uses AES-CTR and SHA2 as primitives instead +# 90s mode uses AES256-CTR and SHA2 as primitives instead +# Uses a bitslice implementation 90s = ["sha2"] +# Fixslice RustCrypto AES implementation offers some additional sidechannel +# attack resistance. Suggest benchmarking for comparison. +90s-fixslice = ["90s", "aes", "ctr"] + # Use avx2 intrinsics on x86 architectures -# Wont compile if the platform doesn't supprt it +# Wont compile if the platform doesn't support it avx2 = ["cc"] # For compiling to wasm targets diff --git a/benches/api.rs b/benches/api.rs index ce114c2..29332f4 100644 --- a/benches/api.rs +++ b/benches/api.rs @@ -1,74 +1,69 @@ +#![cfg(feature = "benchmarking")] // Lint use criterion::{criterion_group, criterion_main, Criterion}; use pqc_kyber::*; // First set in KAT_2400 -const PK_HEX: &str = "A0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922"; -const SK_HEX: &str = "07638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405DA0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922DEE4ABA000389581717D36F56F39AF7300B31D831A4D8C976128E09DEDE71A5A8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F"; +const PK: &str = "A0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922"; +const SK: &str = "07638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405DA0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922DEE4ABA000389581717D36F56F39AF7300B31D831A4D8C976128E09DEDE71A5A8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F"; const BAD_SK: &str = "17638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405DA0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922DEE4ABA000389581717D36F56F39AF7300B31D831A4D8C976128E09DEDE71A5A8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F"; -const CT_HEX: &str = "EADD5ADA14DA57F0AEF3505F1CAA6485D4238D999A3EF4B0A59A1CDBE0A27E478547A3A99D2AB09AC7D7C8F5AE3D6432045CBA3FA778345892542BD81C05BEFCD2E5CC9A579BEFB7C58D02FB94F33392FE17F4EBA2CB510EC74CC9D1D8A87C1066A4869A3983E664BFE9DEA5AE4FDF310C8F59815A678FA325F369AF84FFEBC1D150431FE3BD2734F636CF658E6C1A6A6E2CBE071F9A7C26119AD105098EDA622CAB8E176762109877D9AE9D6729D44A58E707D6B8AD6E696A33C672DA9D08DA2A7F9E3BF02218238722A46B31D49DAFF9AF00A6363C3A423B2E873DEFDDBCD969B75A81053D9A97C06DE2BFE3D0CFD3D3C77983B18DBDE23C0728604A71435AD40DF1579096DDBE02E4612210CAA034DCEFB8B4D7B5E6D2EBA37A79FB61F34B5AF7D9B27B13E4936222411249B7FBB69E73461DAF4AA6F3E2C73944F10CE67C86FED260BDA7B40DB39B1DE3C7D8F09A77F3C84BC62931D228B24A574AC3F4EB745CFF7E031A3FB2A08595C15370A3C82DB7D9F41BB1D8ECC429CFA3A65833016AB6EA60C9390CFA1B65CCEAE550940795386ED24133FBAE8B3017502AF3CFE951D781D36CFEFF85BFDF5AF040BE4065681B3B0A63C2747F0808CF3DA725169DDED1003DA6CD5DE4CB041942938D0A7F8802D48F2E3C6EEB45CD90AF6FC9F4507E9F8380AC33CACA7751487F65500441D920B94880A497D01C0802BB08D74C5D4C6BF2D865EE5822B3375C755D1A5E3D3244C320510A1E30357702CD4252072CF86437F7A9DE5561C7E59B94B9584100131AC399F4C1EB19FB4BDF65E62785E97C194B8764CCF32FD05D804C2E439DDA2A109274FBFFA81A837C51B26D154F974B882A5B174B308FC48768D222922532B183ABDF6FBB0BC7492766974D321EE6FB7C5F7B3EEA2378DC6D6BB48019250B8D8D8DEDB522421AEEDB318676982A80E7961EC40E6D7F3339694255BAFF51BE3A7EA7D8793A109BE3AE4423BF082E206A573B4F0F93FC16DDE81BD5DC583F528C08A0A9AB8E6CD524E297C9CF0F43C344913830ECB16F91441477BA782EDD4E73E732979D3A664EB99EA5D24B6C84AA69F377CB0CAD5AE4E641E38B197A0994D58B2387E91760E9B6FEBCB445CF85BBA24A94CDA75E338674428249FE6DE4692601D1EAE0EA021D9BC8077BE8665D0737748FA30FCF80F7E482584674F633A5006A538267627FD91854E0871268A6B0B05DD51495135DEFB9376E9B841B64E5DBF43CE6C74BCF3AE1FC427E810B7CBF6957DBF904690E87842543897DE78F13D08D92EBD27FB2CFCC0C765430589057B16B15F207CA1E6F08D52616DD57AD43EFEA6FDDAAEA18D33731FAC7ECAAE950E1DF3C5A4E6FCB223DF5E86B487FD7092D0822EFFAEC82C4BEC10C600FDB90E77482911B1595277738841409D0F8F113191D47F5E56C115A05DEA759AA6FB1D047F9FCA4ED519EA5D21FE3BA5B9434FEA1283DFAD63D01589B0EB61F244351D03341DCD4DF62265AFCAEC6676A877D5CACB359EBB5319610DD447DA97E950B0C"; +const CT: &str = "EADD5ADA14DA57F0AEF3505F1CAA6485D4238D999A3EF4B0A59A1CDBE0A27E478547A3A99D2AB09AC7D7C8F5AE3D6432045CBA3FA778345892542BD81C05BEFCD2E5CC9A579BEFB7C58D02FB94F33392FE17F4EBA2CB510EC74CC9D1D8A87C1066A4869A3983E664BFE9DEA5AE4FDF310C8F59815A678FA325F369AF84FFEBC1D150431FE3BD2734F636CF658E6C1A6A6E2CBE071F9A7C26119AD105098EDA622CAB8E176762109877D9AE9D6729D44A58E707D6B8AD6E696A33C672DA9D08DA2A7F9E3BF02218238722A46B31D49DAFF9AF00A6363C3A423B2E873DEFDDBCD969B75A81053D9A97C06DE2BFE3D0CFD3D3C77983B18DBDE23C0728604A71435AD40DF1579096DDBE02E4612210CAA034DCEFB8B4D7B5E6D2EBA37A79FB61F34B5AF7D9B27B13E4936222411249B7FBB69E73461DAF4AA6F3E2C73944F10CE67C86FED260BDA7B40DB39B1DE3C7D8F09A77F3C84BC62931D228B24A574AC3F4EB745CFF7E031A3FB2A08595C15370A3C82DB7D9F41BB1D8ECC429CFA3A65833016AB6EA60C9390CFA1B65CCEAE550940795386ED24133FBAE8B3017502AF3CFE951D781D36CFEFF85BFDF5AF040BE4065681B3B0A63C2747F0808CF3DA725169DDED1003DA6CD5DE4CB041942938D0A7F8802D48F2E3C6EEB45CD90AF6FC9F4507E9F8380AC33CACA7751487F65500441D920B94880A497D01C0802BB08D74C5D4C6BF2D865EE5822B3375C755D1A5E3D3244C320510A1E30357702CD4252072CF86437F7A9DE5561C7E59B94B9584100131AC399F4C1EB19FB4BDF65E62785E97C194B8764CCF32FD05D804C2E439DDA2A109274FBFFA81A837C51B26D154F974B882A5B174B308FC48768D222922532B183ABDF6FBB0BC7492766974D321EE6FB7C5F7B3EEA2378DC6D6BB48019250B8D8D8DEDB522421AEEDB318676982A80E7961EC40E6D7F3339694255BAFF51BE3A7EA7D8793A109BE3AE4423BF082E206A573B4F0F93FC16DDE81BD5DC583F528C08A0A9AB8E6CD524E297C9CF0F43C344913830ECB16F91441477BA782EDD4E73E732979D3A664EB99EA5D24B6C84AA69F377CB0CAD5AE4E641E38B197A0994D58B2387E91760E9B6FEBCB445CF85BBA24A94CDA75E338674428249FE6DE4692601D1EAE0EA021D9BC8077BE8665D0737748FA30FCF80F7E482584674F633A5006A538267627FD91854E0871268A6B0B05DD51495135DEFB9376E9B841B64E5DBF43CE6C74BCF3AE1FC427E810B7CBF6957DBF904690E87842543897DE78F13D08D92EBD27FB2CFCC0C765430589057B16B15F207CA1E6F08D52616DD57AD43EFEA6FDDAAEA18D33731FAC7ECAAE950E1DF3C5A4E6FCB223DF5E86B487FD7092D0822EFFAEC82C4BEC10C600FDB90E77482911B1595277738841409D0F8F113191D47F5E56C115A05DEA759AA6FB1D047F9FCA4ED519EA5D21FE3BA5B9434FEA1283DFAD63D01589B0EB61F244351D03341DCD4DF62265AFCAEC6676A877D5CACB359EBB5319610DD447DA97E950B0C"; // Benchmarking key generation -fn keypair_bench(c: &mut Criterion) { - let mut rng = rand::thread_rng(); - c.bench_function( - "Keypair Generation", - |b| b.iter( - || { - let _keys = keypair(&mut rng); - } - ) - ); +fn keypair(c: &mut Criterion) { + let mut _rng = rand::thread_rng(); //placeholder + let mut pk = [0u8; KYBER_PUBLICKEYBYTES]; + let mut sk = [0u8; KYBER_SECRETKEYBYTES]; + let bufs = Some(([1u8; 32].as_slice(), [255u8; 32].as_slice())); + c.bench_function("Keypair Generation", |b| { + b.iter(|| { + crypto_kem_keypair(&mut pk, &mut sk, &mut _rng, bufs); + }) + }); } // Encapsulating a single public key -fn encap_bench(c: &mut Criterion) { - let pk = crate::decode_hex(PK_HEX); - let mut rng = rand::thread_rng(); - c.bench_function( - "Encapsulate", - |b| b.iter( - || { - let _enc = encapsulate(&pk, &mut rng); - } - ) - ); +fn encap(c: &mut Criterion) { + let mut ct = [0u8; KYBER_CIPHERTEXTBYTES]; + let mut ss = [0u8; KYBER_SSBYTES]; + let pk = crate::decode_hex(PK); + let mut _rng = rand::thread_rng(); + let encap_buf = Some([255u8; 32].as_slice()); + c.bench_function("Encapsulate", |b| { + b.iter(|| { + crypto_kem_enc(&mut ct, &mut ss, &pk, &mut _rng, encap_buf); + }) + }); } // Decapsulating a single correct ciphertext -fn decap_bench(c: &mut Criterion) { - let sk = decode_hex(SK_HEX); - let ct = decode_hex(CT_HEX); - c.bench_function( - "Decapsulate", - |b| b.iter( - || { - let _dec = decapsulate(&ct, &sk); - } - ) - ); +fn decap(c: &mut Criterion) { + let sk = decode_hex(SK); + let ct = decode_hex(CT); + c.bench_function("Decapsulate", |b| { + b.iter(|| { + let _dec = decapsulate(&ct, &sk); + }) + }); } // Decapsulating a single incorrect ciphertext -fn decap_fail_bench(c: &mut Criterion) { +fn decap_fail(c: &mut Criterion) { let sk = decode_hex(BAD_SK); - let ct = decode_hex(CT_HEX); - c.bench_function( - "Decapsulate Failure", - |b| b.iter( - || { - let _dec = decapsulate(&ct, &sk); - } - ) - ); + let ct = decode_hex(CT); + c.bench_function("Decapsulate Failure", |b| { + b.iter(|| { + let _dec = decapsulate(&ct, &sk); + }) + }); } -criterion_group!(benches, keypair_bench, encap_bench, decap_bench, decap_fail_bench); +criterion_group!(benches, keypair, encap, decap, decap_fail); criterion_main!(benches); // Decodes a hex string into a vector of bytes pub fn decode_hex(s: &str) -> Vec { (0..s.len()) - .step_by(2) - .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("Hex string decoding")) - .collect::>() -} \ No newline at end of file + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("Hex string decoding")) + .collect::>() +} diff --git a/contributing.md b/contributing.md index f9579e2..3cc7303 100644 --- a/contributing.md +++ b/contributing.md @@ -2,13 +2,11 @@ Contributions always welcome. Checkout the development branch create a feature fork and submit a PR back to the development branch. If possible please run a benchmark first for any significant regressions. -Current areas of focus aka "aspirational TODO's": +Current areas of focus: * **Neon ARM intrinsics** - There is a [neon library](https://github.com/cothan/kyber/tree/round3/neon) for Kyber, though currently many ARM intrinsics still don't exist in rust, so there's two branches, `neon` is a rust port of his work that will have to wait until the intrinsics are upstream, `neon_c` is using the original C code with a FFI. * **Optimizations** - See the benchmarking readme, possibly some fat that can still be trimmed off. -* **Add RustCrypto primitives feature for 90s mode** - This is half done yet commented out, still needs some cleaning up to fit in. * **Serde** - Implement Serialize/Deserialize traits for the structs and put it behind a feature gate. -* **NASM** - The assembly code is written in GAS, for more portability it would be ideal if it was converted NASM or MASM so it can be used on windows. * **Mutually Exclusive Features** Currently the crate has all the variants behind feature gates that can't be used together, this is an antipattern in rust, the alternatives are to split the crate up with a lot code of code duplication and maintain them all separately, or make many functions generic, neither are ideal or easy to do. By submitting any code to this repository you agree to have it licensed under both Apache 2.0 and MIT. \ No newline at end of file diff --git a/examples/ake.rs b/examples/ake.rs index de0e330..7b2cdd0 100644 --- a/examples/ake.rs +++ b/examples/ake.rs @@ -14,11 +14,11 @@ fn main() -> Result<(), KyberError> { // Bob receives the request and authenticates Alice, sends // encapsulated shared secret back let server_send = bob.server_receive( - client_send, &alice_keys.public, &bob_keys.secret, &mut rng + client_send, &alice_keys.public, bob_keys.expose_secret(), &mut rng )?; - // Alice autheticates and decapsulates - alice.client_confirm(server_send, &alice_keys.secret)?; + // Alice authenticates and decapsulates + alice.client_confirm(server_send, alice_keys.expose_secret())?; // Both structs now have the shared secret assert_eq!(alice.shared_secret, bob.shared_secret); diff --git a/examples/kem.rs b/examples/kem.rs index a50de8e..92b50f2 100644 --- a/examples/kem.rs +++ b/examples/kem.rs @@ -10,9 +10,9 @@ fn main () -> Result<(), KyberError> { let (ciphertext, shared_secret_bob) = encapsulate(&alice_keys.public, &mut rng)?; // Alice decapsulates the shared secret - let shared_secret_alice = decapsulate(&ciphertext, &alice_keys.secret)?; + let shared_secret_alice = decapsulate(&ciphertext, alice_keys.expose_secret())?; - // Both can now communicate symetrically + // Both can now communicate symmetrically assert_eq!(shared_secret_alice, shared_secret_bob); Ok(()) } \ No newline at end of file diff --git a/examples/uake.rs b/examples/uake.rs index f59c0b6..e1f39e6 100644 --- a/examples/uake.rs +++ b/examples/uake.rs @@ -14,10 +14,10 @@ fn main() -> Result<(), KyberError> { // Bob receives the request and authenticates Alice, sends // encapsulated shared secret back let server_send = bob.server_receive( - client_send, &bob_keys.secret, &mut rng + client_send, bob_keys.expose_secret(), &mut rng )?; - // Alice autheticates and decapsulates + // Alice authenticates and decapsulates alice.client_confirm(server_send)?; // Both structs now have the shared secret diff --git a/readme.md b/readme.md index c4323db..8658bd7 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,7 @@ It is recommended to use Kyber in a hybrid system alongside a traditional key ex Please also read the [**security considerations**](#security-considerations) before use. -**Minimum Supported Rust Version: 1.47.0** +**Minimum Supported Rust Version: 1.56.0** --- @@ -60,7 +60,7 @@ let keys_bob = keypair(&mut rng); let (ciphertext, shared_secret_alice) = encapsulate(&keys_bob.public, &mut rng)?; // Bob decapsulates a shared secret using the ciphertext sent by Alice -let shared_secret_bob = decapsulate(&ciphertext, &keys_bob.secret)?; +let shared_secret_bob = decapsulate(&ciphertext, keys_bob.expose_secret())?; assert_eq!(shared_secret_alice, shared_secret_bob); ``` @@ -83,7 +83,7 @@ let client_init = alice.client_init(&bob_keys.public, &mut rng); // Bob authenticates and responds let server_response = bob.server_receive( - client_init, &bob_keys.secret, &mut rng + client_init, bob_keys.expose_secret(), &mut rng )?; // Alice decapsulates the shared secret @@ -108,10 +108,10 @@ let bob_keys = keypair(&mut rng); let client_init = alice.client_init(&bob_keys.public, &mut rng); let server_response = bob.server_receive( - client_init, &alice_keys.public, &bob_keys.secret, &mut rng + client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng )?; -alice.client_confirm(server_response, &alice_keys.secret)?; +alice.client_confirm(server_response, alice_keys.expose_secret())?; assert_eq!(alice.shared_secret, bob.shared_secret); ``` @@ -139,15 +139,16 @@ pqc_kyber = {version = "0.4.0", features = ["kyber512", "90s", "avx2"]} | Feature | Description | |-----------|------------| +| std | Enable the standard library | | kyber512 | Enables kyber512 mode, with a security level roughly equivalent to AES-128.| | kyber1024 | Enables kyber1024 mode, with a security level roughly equivalent to AES-256. A compile-time error is raised if more than one security level is specified.| -| 90s | Uses SHA2 and AES in counter mode as a replacement for SHAKE. This can provide hardware speedups in some cases. | +| 90s | Uses AES256 in counter mode and SHA2 as a replacement for SHAKE. This can provide hardware speedups in some cases.| +| 90s-fixslice | Uses a fixslice implementation of AES256 by RustCrypto, this provides greater side-channel attack resistance, especially on embedded platforms | | avx2 | On x86_64 platforms enable the optimized version. This flag is will cause a compile error on other architectures. | | wasm | For compiling to WASM targets| | nasm | Uses Netwide Assembler avx2 code instead of GAS for portability. Requires a nasm compiler: https://www.nasm.us/ | | zeroize | This will zero out the key exchange structs on drop using the [zeroize](https://docs.rs/zeroize/latest/zeroize/) crate | -| std | Enable the standard library | -| benchmarking | Enables the criterion benchmarking suite | +| benchmarking | Enables the criterion benchmarking suite | --- ## Testing diff --git a/src/api.rs b/src/api.rs index 661efdf..ff53658 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; +use pqc_core::zero; use crate::{ params::*, error::KyberError, @@ -11,10 +14,8 @@ use crate::{ /// ### Example /// ``` /// # use pqc_kyber::*; -/// # fn main() -> Result<(), KyberError> { /// let mut rng = rand::thread_rng(); /// let keys = keypair(&mut rng); -/// # Ok(())} /// ``` pub fn keypair(rng: &mut R) -> Keypair where R: RngCore + CryptoRng @@ -22,7 +23,9 @@ pub fn keypair(rng: &mut R) -> Keypair let mut public = [0u8; KYBER_PUBLICKEYBYTES]; let mut secret = [0u8; KYBER_SECRETKEYBYTES]; crypto_kem_keypair(&mut public, &mut secret, rng, None); - Keypair { public, secret } + let keys = Keypair { public, secret }; + zero!(secret); + keys } /// Encapsulates a public key returning the ciphertext to send @@ -37,7 +40,7 @@ pub fn keypair(rng: &mut R) -> Keypair /// let (ciphertext, shared_secret) = encapsulate(&keys.public, &mut rng)?; /// # Ok(())} /// ``` -pub fn encapsulate(pk: &[u8], rng: &mut R) -> Encapsulated +pub fn encapsulate(pk: &[u8], rng: &mut R) -> Encapsulated where R: CryptoRng + RngCore { if pk.len() != KYBER_PUBLICKEYBYTES { @@ -48,7 +51,7 @@ pub fn encapsulate(pk: &[u8], rng: &mut R) -> Encapsulated crypto_kem_enc(&mut ct, &mut ss, pk, rng, None); Ok((ct, ss)) } - + /// Decapsulates ciphertext with a secret key, the result will contain /// a KyberError if decapsulation fails /// @@ -59,7 +62,7 @@ pub fn encapsulate(pk: &[u8], rng: &mut R) -> Encapsulated /// let mut rng = rand::thread_rng(); /// let keys = keypair(&mut rng); /// let (ct, ss1) = encapsulate(&keys.public, &mut rng)?; -/// let ss2 = decapsulate(&ct, &keys.secret)?; +/// let ss2 = decapsulate(&ct, keys.expose_secret())?; /// assert_eq!(ss1, ss2); /// # Ok(())} /// ``` @@ -78,26 +81,63 @@ pub fn decapsulate(ct: &[u8], sk: &[u8]) -> Decapsulated /// A public/secret keypair for use with Kyber. /// /// Byte lengths of the keys are determined by the security level chosen. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone)] pub struct Keypair { pub public: PublicKey, - pub secret: SecretKey + secret: SecretKey, } impl Keypair { /// Securely generates a new keypair` /// ``` /// # use pqc_kyber::*; - /// # fn main() -> Result<(), KyberError> { /// let mut rng = rand::thread_rng(); /// let keys = Keypair::generate(&mut rng); - /// # let empty_keys = Keypair{ - /// public: [0u8; KYBER_PUBLICKEYBYTES], secret: [0u8; KYBER_SECRETKEYBYTES] - /// }; - /// # assert!(empty_keys != keys); - /// # Ok(()) } /// ``` pub fn generate(rng: &mut R) -> Keypair { keypair(rng) } -} \ No newline at end of file + + /// Explicitly exposes the secret key + ///``` + /// # use pqc_kyber::*; + /// # let mut rng = rand::thread_rng(); + /// let keys = Keypair::generate(&mut rng); + /// let secret = keys.expose_secret(); + /// # assert!(secret.len() == KYBER_SECRETKEYBYTES); + /// ``` + pub fn expose_secret(&self) -> &SecretKey { + &self.secret + } +} + +#[cfg(feature = "zeroize")] +impl Drop for Keypair { + fn drop(&mut self) { + self.secret.zeroize() + } +} + +/// Elides the secret key, to debug it use [`Keypair::expose_secret()`] +impl core::fmt::Debug for Keypair { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{{ public: '{:x?}',\n secret: 'ELIDED'}}", self.public) + } +} + +/// Ignores secret key to avoid leakage from of a non-cryptographic hasher +impl core::hash::Hash for Keypair { + fn hash(&self, state: &mut H) { + self.public.hash(state); + } +} + +/// Non-constant time equality comparison, only checks public keys +impl PartialEq for Keypair { + fn eq(&self, other: &Keypair) -> bool { + self.public == other.public + } +} + +impl Eq for Keypair {} + diff --git a/src/kem.rs b/src/kem.rs index e902f8f..50ea19d 100644 --- a/src/kem.rs +++ b/src/kem.rs @@ -1,10 +1,13 @@ -use crate::rng::randombytes; +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; +use pqc_core::zero; use rand_core::{RngCore, CryptoRng}; use crate::{ params::*, indcpa::*, symmetric::*, error::KyberError, + rng::randombytes, verify::* }; @@ -63,6 +66,7 @@ pub fn crypto_kem_enc( // Don't release system RNG output hash_h(&mut buf, &randbuf, KYBER_SYMBYTES); + zero!(randbuf); // Multitarget countermeasure for coins + contributory KEM hash_h(&mut buf[KYBER_SYMBYTES..], pk, KYBER_PUBLICKEYBYTES); @@ -70,12 +74,14 @@ pub fn crypto_kem_enc( // coins are in kr[KYBER_SYMBYTES..] indcpa_enc(ct, &buf, pk, &kr[KYBER_SYMBYTES..]); + zero!(buf); // overwrite coins in kr with H(c) hash_h(&mut kr[KYBER_SYMBYTES..], ct, KYBER_CIPHERTEXTBYTES); // hash concatenation of pre-k and H(c) to k kdf(ss, &kr, 2*KYBER_SYMBYTES); + zero!(kr); } // Name: crypto_kem_dec @@ -117,6 +123,7 @@ pub fn crypto_kem_dec( cmov(&mut kr, &sk[END..], KYBER_SYMBYTES, fail); // hash concatenation of pre-k and H(c) to k kdf(ss, &kr, 2*KYBER_SYMBYTES); + zero!(kr); match fail { 0 => Ok(()), diff --git a/src/kex.rs b/src/kex.rs index 3300dba..c70a93f 100644 --- a/src/kex.rs +++ b/src/kex.rs @@ -1,6 +1,6 @@ use rand_core::{RngCore, CryptoRng}; #[cfg(feature = "zeroize")] -use zeroize::{Zeroize, ZeroizeOnDrop}; +use zeroize::Zeroize; use crate::{ kem::*, symmetric::kdf, @@ -52,13 +52,12 @@ type Eska = [u8; KYBER_SECRETKEYBYTES]; /// let bob_keys = keypair(&mut rng); /// /// let client_init = alice.client_init(&bob_keys.public, &mut rng); -/// let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng)?; +/// let server_send = bob.server_receive(client_init, bob_keys.expose_secret(), &mut rng)?; /// let client_confirm = alice.client_confirm(server_send); /// /// assert_eq!(alice.shared_secret, bob.shared_secret); /// # Ok(()) } -#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))] #[derive(Clone, Debug, Eq, PartialEq)] pub struct Uake { /// The resulting shared secret from a key exchange @@ -84,6 +83,17 @@ impl Default for Uake { } } +#[cfg(feature = "zeroize")] +impl Drop for Uake { + fn drop(&mut self) { + self.shared_secret.zeroize(); + self.send_a.zeroize(); + self.send_b.zeroize(); + self.temp_key.zeroize(); + self.eska.zeroize(); + } +} + impl Uake { /// Builds new UAKE struct /// ``` @@ -124,7 +134,7 @@ impl Uake { /// let mut bob = Uake::new(); /// let mut bob_keys = keypair(&mut rng); /// let client_init = alice.client_init(&bob_keys.public, &mut rng); - /// let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng)?; + /// let server_send = bob.server_receive(client_init, bob_keys.expose_secret(), &mut rng)?; /// # Ok(()) } pub fn server_receive( &mut self, send_a: UakeSendInit, secretkey: &SecretKey, rng: &mut R @@ -149,7 +159,7 @@ impl Uake { /// # let mut bob = Uake::new(); /// # let bob_keys = keypair(&mut rng); /// let client_init = alice.client_init(&bob_keys.public, &mut rng); - /// let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng)?; + /// let server_send = bob.server_receive(client_init, bob_keys.expose_secret(), &mut rng)?; /// let client_confirm = alice.client_confirm(server_send); /// assert_eq!(alice.shared_secret, bob.shared_secret); /// # Ok(()) } @@ -179,14 +189,13 @@ impl Uake { /// let bob_keys = keypair(&mut rng); /// /// let client_init = alice.client_init(&bob_keys.public, &mut rng); -/// let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng)?; -/// let client_confirm = alice.client_confirm(server_send, &alice_keys.secret); +/// let server_send = bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng)?; +/// let client_confirm = alice.client_confirm(server_send, alice_keys.expose_secret()); /// /// assert_eq!(alice.shared_secret, bob.shared_secret); /// # Ok(()) } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))] pub struct Ake { /// The resulting shared secret from a key exchange pub shared_secret: SharedSecret, @@ -211,6 +220,17 @@ impl Default for Ake { } } +#[cfg(feature = "zeroize")] +impl Drop for Ake { + fn drop(&mut self) { + self.shared_secret.zeroize(); + self.send_a.zeroize(); + self.send_b.zeroize(); + self.temp_key.zeroize(); + self.eska.zeroize(); + } +} + impl Ake { /// Builds a new AKE struct /// ``` @@ -252,7 +272,7 @@ impl Ake { /// let alice_keys = keypair(&mut rng); /// let bob_keys = keypair(&mut rng); /// let client_init = alice.client_init(&bob_keys.public, &mut rng); - /// let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng)?; + /// let server_send = bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng)?; /// # Ok(()) } pub fn server_receive( &mut self, ake_send_a: AkeSendInit, pubkey: &PublicKey, @@ -279,8 +299,8 @@ impl Ake { /// # let alice_keys = keypair(&mut rng); /// # let bob_keys = keypair(&mut rng); /// # let client_init = alice.client_init(&bob_keys.public, &mut rng); - /// let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng)?; - /// let client_confirm = alice.client_confirm(server_send, &alice_keys.secret); + /// let server_send = bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng)?; + /// let client_confirm = alice.client_confirm(server_send, alice_keys.expose_secret()); /// assert_eq!(alice.shared_secret, bob.shared_secret); /// # Ok(()) } pub fn client_confirm(&mut self, send_b: AkeSendResponse, secretkey: &SecretKey) diff --git a/src/lib.rs b/src/lib.rs index 0736cf6..f13079f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,13 +41,13 @@ //! # fn main() -> Result<(),KyberError> { //! # let mut rng = rand::thread_rng(); //! // Generate Keypair -//! let keys_bob = keypair(&mut rng); +//! let bob_keys = keypair(&mut rng); //! //! // Alice encapsulates a shared secret using Bob's public key -//! let (ciphertext, shared_secret_alice) = encapsulate(&keys_bob.public, &mut rng)?; +//! let (ciphertext, shared_secret_alice) = encapsulate(&bob_keys.public, &mut rng)?; //! //! // Bob decapsulates a shared secret using the ciphertext sent by Alice -//! let shared_secret_bob = decapsulate(&ciphertext, &keys_bob.secret)?; +//! let shared_secret_bob = decapsulate(&ciphertext, bob_keys.expose_secret())?; //! //! assert_eq!(shared_secret_alice, shared_secret_bob); //! # Ok(()) } @@ -74,7 +74,7 @@ //! //! // Bob authenticates and responds //! let server_send = bob.server_receive( -//! client_init, &bob_keys.secret, &mut rng +//! client_init, bob_keys.expose_secret(), &mut rng //! )?; //! //! // Alice decapsulates the shared secret @@ -101,10 +101,10 @@ //! let client_init = alice.client_init(&bob_keys.public, &mut rng); //! //! let server_send = bob.server_receive( -//! client_init, &alice_keys.public, &bob_keys.secret, &mut rng +//! client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng //! )?; //! -//! alice.client_confirm(server_send, &alice_keys.secret)?; +//! alice.client_confirm(server_send, alice_keys.expose_secret())?; //! //! assert_eq!(alice.shared_secret, bob.shared_secret); //! # Ok(()) } @@ -160,5 +160,5 @@ pub use rand_core::{RngCore, CryptoRng}; // Feature hack to expose private functions for the Known Answer Tests // and fuzzing. Will fail to compile if used outside `cargo test` or // the fuzz binaries. -#[cfg(any(kyber_kat, fuzzing))] +#[cfg(any(kyber_kat, fuzzing, feature = "benchmarking"))] pub use kem::*; diff --git a/src/reference/aes256ctr.rs b/src/reference/aes256ctr.rs index ab04efc..d72bac9 100644 --- a/src/reference/aes256ctr.rs +++ b/src/reference/aes256ctr.rs @@ -547,6 +547,7 @@ fn br_aes_ct64_ctr_init(sk_exp: &mut [u64], key: &[u8]) br_aes_ct64_skey_expand(sk_exp, &skey); } +#[cfg(not(feature="90s-fixslice"))] fn br_aes_ct64_ctr_run(sk_exp: &mut[u64], iv: &[u8], cc: u32, data: &mut[u8], mut len: usize) { let mut ivw = [0u32; 16]; @@ -583,6 +584,7 @@ fn br_aes_ct64_ctr_run(sk_exp: &mut[u64], iv: &[u8], cc: u32, data: &mut[u8], mu // - usize outlen: length of requested output in bytes // - const [u8] key: 32-byte key // - const u8 nonce: 1-byte nonce (will be zero-padded to 12 bytes) +#[cfg(not(feature="90s-fixslice"))] pub fn aes256ctr_prf(output: &mut[u8], outlen: usize, key: &[u8], nonce: u8) { let mut sk_exp = [0u64; 120]; diff --git a/src/reference/indcpa.rs b/src/reference/indcpa.rs index f0d1453..42d144d 100644 --- a/src/reference/indcpa.rs +++ b/src/reference/indcpa.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; +use pqc_core::zero; use crate::rng::randombytes; use crate::{ poly::*, @@ -206,8 +209,9 @@ pub fn indcpa_keypair( } hash_g(&mut buf, &randbuf, KYBER_SYMBYTES); + zero!(randbuf); - let (publicseed, noiseseed) = buf.split_at(KYBER_SYMBYTES); + let (publicseed, noiseseed) = buf.split_at_mut(KYBER_SYMBYTES); gen_a(&mut a, publicseed); for i in 0..KYBER_K { @@ -217,7 +221,7 @@ pub fn indcpa_keypair( for i in 0..KYBER_K { poly_getnoise_eta1(&mut e.vec[i], noiseseed, nonce); nonce += 1; - } + } polyvec_ntt(&mut skpv); polyvec_ntt(&mut e); @@ -232,6 +236,7 @@ pub fn indcpa_keypair( pack_sk(sk, &mut skpv); pack_pk(pk, &mut pkpv, publicseed); + zero!(buf); } // Name: indcpa_enc @@ -285,6 +290,8 @@ pub fn indcpa_enc(c: &mut[u8], m: &[u8], pk: &[u8], coins: &[u8]) poly_reduce(&mut v); pack_ciphertext(c, &mut b, v); + zero!(b); + zero!(v); } // Name: indcpa_dec @@ -305,6 +312,8 @@ pub fn indcpa_dec(m: &mut[u8], c: &[u8], sk: &[u8]) polyvec_ntt(&mut b); polyvec_basemul_acc_montgomery(&mut mp, &skpv, &b); + zero!(skpv); + zero!(b); poly_invntt_tomont(&mut mp); poly_sub(&mut mp, &v); diff --git a/src/reference/poly.rs b/src/reference/poly.rs index 9d307aa..edb52a3 100644 --- a/src/reference/poly.rs +++ b/src/reference/poly.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + use crate::{ params::*, ntt::*, @@ -28,6 +31,13 @@ impl Poly { } } +#[cfg(feature = "zeroize")] +impl Zeroize for Poly { + fn zeroize(&mut self) { + self.coeffs.zeroize(); + } +} + // Name: poly_compress // // Description: Compression and subsequent serialization of a polynomial diff --git a/src/reference/polyvec.rs b/src/reference/polyvec.rs index e1361d8..a543983 100644 --- a/src/reference/polyvec.rs +++ b/src/reference/polyvec.rs @@ -1,4 +1,8 @@ #![allow(clippy::precedence)] + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + use crate::{ poly::*, params::* @@ -19,6 +23,13 @@ impl Polyvec { } } +#[cfg(feature = "zeroize")] +impl Zeroize for Polyvec { + fn zeroize(&mut self) { + self.vec.iter_mut().zeroize(); + } +} + // Name: polyvec_compress // // Description: Compress and serialize vector of polynomials diff --git a/src/symmetric.rs b/src/symmetric.rs index efec75a..8f44588 100644 --- a/src/symmetric.rs +++ b/src/symmetric.rs @@ -1,205 +1,205 @@ -#![allow(dead_code)] - -#[cfg(not(feature = "90s"))] use crate::{fips202::*, params::*}; -#[cfg(feature = "90s")] use crate::aes256ctr::*; -#[cfg(feature = "90s")] use sha2::{Sha256, Sha512, Digest}; -// TODO: Rustrypto AES-CTR feature -// #[cfg(feature = "90s")] use aes_ctr::Aes256Ctr; -// #[cfg(feature = "90s")] use aes_ctr::cipher::{ -// generic_array::GenericArray, -// stream::{NewStreamCipher, SyncStreamCipher} -// }; - -#[cfg(feature = "90s")] -pub(crate) const AES256CTR_BLOCKBYTES: usize = 64; - -#[cfg(feature = "90s")] -pub(crate) const XOF_BLOCKBYTES: usize = AES256CTR_BLOCKBYTES; -#[cfg(not(feature = "90s"))] -pub(crate) const XOF_BLOCKBYTES: usize = SHAKE128_RATE; - -#[cfg(not(feature = "90s"))] -pub(crate) type XofState = KeccakState; - -#[cfg(feature = "90s")] -pub(crate) type XofState = Aes256CtrCtx; - -#[derive(Copy, Clone)] -pub(crate) struct KeccakState { - pub s: [u64; 25], - pub pos: usize -} - -impl KeccakState { - pub fn new() -> Self { - KeccakState { - s: [0u64; 25], - pos: 0usize - } - } - - pub fn reset(&mut self) { - self.s = [0u64; 25]; - self.pos = 0; - } -} - -// SHA3-256 -#[cfg(not(feature = "90s"))] -pub(crate) fn hash_h(out: &mut[u8], input: &[u8], inlen: usize) -{ - sha3_256(out, input, inlen); -} - -// 90s mode SHA2-256 -#[cfg(feature = "90s")] -pub(crate) fn hash_h(out: &mut[u8], input: &[u8], inlen: usize) -{ - let mut hasher = Sha256::new(); - hasher.update(&input[..inlen]); - let digest = hasher.finalize(); - out[..digest.len()].copy_from_slice(&digest); -} - -#[cfg(not(feature = "90s"))] -pub(crate) fn hash_g(out: &mut[u8], input: &[u8], inlen: usize) -{ - sha3_512(out, input, inlen); -} - -#[cfg(feature = "90s")] -pub(crate) fn hash_g(out: &mut[u8], input: &[u8], inlen: usize) -{ - let mut hasher = Sha512::new(); - hasher.update(&input[..inlen]); - let digest = hasher.finalize(); - out[..digest.len()].copy_from_slice(&digest); -} - -#[cfg(not(feature = "90s"))] -pub(crate) fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8) -{ - kyber_shake128_absorb(state, &input, x, y); -} - -#[cfg(feature = "90s")] -pub(crate) fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8) -{ - let mut nonce = [0u8; 12]; - nonce[0] = x; - nonce[1] = y; - aes256ctr_init(state, &input, nonce); -} - -#[cfg(not(feature = "90s"))] -pub(crate) fn xof_squeezeblocks(out: &mut[u8], outblocks: usize, state: &mut XofState) -{ - kyber_shake128_squeezeblocks(out, outblocks, state); -} - -#[cfg(feature = "90s")] -pub(crate) fn xof_squeezeblocks(out: &mut[u8], outblocks: usize, state: &mut XofState) -{ - aes256ctr_squeezeblocks(out, outblocks, state); -} - -#[cfg(not(feature = "90s"))] -pub(crate) fn prf(out: &mut[u8], outbytes: usize, key: &[u8], nonce: u8) -{ - shake256_prf(out, outbytes, &key, nonce); -} - -#[cfg(feature = "90s")] -pub(crate) fn prf(out: &mut[u8], outbytes: usize, key: &[u8], nonce: u8) -{ - aes256ctr_prf(out, outbytes, &key, nonce); - - // TODO: Add feature to use RustCrypto AES_CTR - // implementation with no lookup tables - // Perhaps add an option for ring also. - - // Working RustCrypto code: - // if cfg!(feature = "rustcrypto-aes") { - // let mut expnonce = [0u8; 16]; - // expnonce[0] = nonce; - // let key = GenericArray::from_slice(key); - // let iv = GenericArray::from_slice(&expnonce); - // let mut cipher = Aes256Ctr::new(&key, &iv); - // cipher.apply_keystream(out); - // } -} - -#[cfg(not(feature = "90s"))] -pub(crate) fn kdf(out: &mut[u8], input: &[u8], inlen: usize) -{ - shake256(out, KYBER_SSBYTES, input, inlen); -} - -#[cfg(feature = "90s")] -pub(crate) fn kdf(out: &mut[u8], input: &[u8], inlen: usize) -{ - let mut hasher = Sha256::new(); - hasher.update(&input[..inlen]); - let digest = hasher.finalize(); - out[..digest.len()].copy_from_slice(&digest); -} - -// Name: kyber_shake128_absorb -// -// Description: Absorb step of the SHAKE128 specialized for the Kyber context. -// -// Arguments: - u64 *s: (uninitialized) output Keccak state -// - const [u8] input: KYBER_SYMBYTES input to be absorbed into s -// - u8 x additional byte of input -// - u8 y additional byte of input -#[cfg(not(feature = "90s"))] -fn kyber_shake128_absorb( - s: &mut KeccakState, - input: &[u8], - x: u8, - y: u8 -) -{ - let mut extseed = [0u8; KYBER_SYMBYTES + 2]; - extseed[..KYBER_SYMBYTES].copy_from_slice(input); - extseed[KYBER_SYMBYTES] = x; - extseed[KYBER_SYMBYTES+1] = y; - shake128_absorb_once(s, &extseed, KYBER_SYMBYTES + 2); -} - -// Name: kyber_shake128_squeezeblocks -// -// Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of SHAKE128_RATE bytes each. -// Modifies the state. Can be called multiple times to keep squeezing, -// i.e., is incremental. -// -// Arguments: - [u8] output: output blocks -// - u64 nblocks: number of blocks to be squeezed (written to output) -// - keccak_state *s: in/output Keccak state -#[cfg(not(feature = "90s"))] -fn kyber_shake128_squeezeblocks( - output: &mut[u8], - nblocks: usize, - s: &mut KeccakState -) -{ - shake128_squeezeblocks(output, nblocks, s); -} - -// Name: shake256_prf -// -// Description: Usage of SHAKE256 as a PRF, concatenates secret and public input -// and then generates outlen bytes of SHAKE256 output -// -// Arguments: - [u8] output: output -// - u64 outlen: number of requested output bytes -// - const [u8] key: the key (of length KYBER_SYMBYTES) -// - const [u8] nonce: single-byte nonce (public PRF input) -#[cfg(not(feature = "90s"))] -fn shake256_prf(output: &mut[u8], outlen: usize, key: &[u8], nonce: u8) -{ - let mut extkey = [0u8; KYBER_SYMBYTES+1]; - extkey[..KYBER_SYMBYTES].copy_from_slice(key); - extkey[KYBER_SYMBYTES] = nonce; - shake256(output, outlen, &extkey, KYBER_SYMBYTES + 1); -} +#![allow(dead_code)] + +#[cfg(feature = "90s")] +use crate::aes256ctr::*; +#[cfg(not(feature = "90s"))] +use crate::{fips202::*, params::*}; +#[cfg(feature = "90s")] +use sha2::{Digest, Sha256, Sha512}; + +#[cfg(feature = "90s-fixslice")] +use aes::cipher::{generic_array::GenericArray, KeyIvInit, StreamCipher}; +#[cfg(feature = "90s-fixslice")] +type Aes256Ctr = ctr::Ctr32BE; + +#[cfg(feature = "90s")] +pub(crate) const AES256CTR_BLOCKBYTES: usize = 64; + +#[cfg(feature = "90s")] +pub(crate) const XOF_BLOCKBYTES: usize = AES256CTR_BLOCKBYTES; +#[cfg(not(feature = "90s"))] +pub(crate) const XOF_BLOCKBYTES: usize = SHAKE128_RATE; + +#[cfg(not(feature = "90s"))] +pub(crate) type XofState = KeccakState; + +#[cfg(feature = "90s")] +pub(crate) type XofState = Aes256CtrCtx; + +#[derive(Copy, Clone)] +pub(crate) struct KeccakState { + pub s: [u64; 25], + pub pos: usize +} + +impl KeccakState { + pub fn new() -> Self { + KeccakState { + s: [0u64; 25], + pos: 0usize + } + } + + pub fn reset(&mut self) { + self.s = [0u64; 25]; + self.pos = 0; + } +} + +// SHA3-256 +#[cfg(not(feature = "90s"))] +pub(crate) fn hash_h(out: &mut[u8], input: &[u8], inlen: usize) +{ + sha3_256(out, input, inlen); +} + +// 90s mode SHA2-256 +#[cfg(feature = "90s")] +pub(crate) fn hash_h(out: &mut[u8], input: &[u8], inlen: usize) +{ + let mut hasher = Sha256::new(); + hasher.update(&input[..inlen]); + let digest = hasher.finalize(); + out[..digest.len()].copy_from_slice(&digest); +} + +#[cfg(not(feature = "90s"))] +pub(crate) fn hash_g(out: &mut[u8], input: &[u8], inlen: usize) +{ + sha3_512(out, input, inlen); +} + +#[cfg(feature = "90s")] +pub(crate) fn hash_g(out: &mut[u8], input: &[u8], inlen: usize) +{ + let mut hasher = Sha512::new(); + hasher.update(&input[..inlen]); + let digest = hasher.finalize(); + out[..digest.len()].copy_from_slice(&digest); +} + +#[cfg(not(feature = "90s"))] +pub(crate) fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8) +{ + kyber_shake128_absorb(state, &input, x, y); +} + +#[cfg(feature = "90s")] +pub(crate) fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8) +{ + let mut nonce = [0u8; 12]; + nonce[0] = x; + nonce[1] = y; + aes256ctr_init(state, &input, nonce); +} + +#[cfg(not(feature = "90s"))] +pub(crate) fn xof_squeezeblocks(out: &mut[u8], outblocks: usize, state: &mut XofState) +{ + kyber_shake128_squeezeblocks(out, outblocks, state); +} + +#[cfg(feature = "90s")] +pub(crate) fn xof_squeezeblocks(out: &mut[u8], outblocks: usize, state: &mut XofState) +{ + aes256ctr_squeezeblocks(out, outblocks, state); +} + +#[cfg(not(feature = "90s"))] +pub(crate) fn prf(out: &mut[u8], outbytes: usize, key: &[u8], nonce: u8) +{ + shake256_prf(out, outbytes, &key, nonce); +} + +#[cfg(feature = "90s")] +pub fn prf(out: &mut [u8], _outbytes: usize, key: &[u8], nonce: u8) { + #[cfg(feature = "90s-fixslice")] + { + // RustCrypto fixslice + let mut expnonce = [0u8; 16]; + expnonce[0] = nonce; + let key = GenericArray::from_slice(key); + let iv = GenericArray::from_slice(&expnonce); + let mut cipher = Aes256Ctr::new(&key, &iv); + cipher.apply_keystream(out); + return + } + #[cfg(not(feature = "90s-fixslice"))] + // Pornin bitslice + aes256ctr_prf(out, _outbytes, &key, nonce); +} + +#[cfg(not(feature = "90s"))] +pub(crate) fn kdf(out: &mut[u8], input: &[u8], inlen: usize) +{ + shake256(out, KYBER_SSBYTES, input, inlen); +} + +#[cfg(feature = "90s")] +pub(crate) fn kdf(out: &mut[u8], input: &[u8], inlen: usize) +{ + let mut hasher = Sha256::new(); + hasher.update(&input[..inlen]); + let digest = hasher.finalize(); + out[..digest.len()].copy_from_slice(&digest); +} + +// Name: kyber_shake128_absorb +// +// Description: Absorb step of the SHAKE128 specialized for the Kyber context. +// +// Arguments: - u64 *s: (uninitialized) output Keccak state +// - const [u8] input: KYBER_SYMBYTES input to be absorbed into s +// - u8 x additional byte of input +// - u8 y additional byte of input +#[cfg(not(feature = "90s"))] +fn kyber_shake128_absorb( + s: &mut KeccakState, + input: &[u8], + x: u8, + y: u8 +) +{ + let mut extseed = [0u8; KYBER_SYMBYTES + 2]; + extseed[..KYBER_SYMBYTES].copy_from_slice(input); + extseed[KYBER_SYMBYTES] = x; + extseed[KYBER_SYMBYTES+1] = y; + shake128_absorb_once(s, &extseed, KYBER_SYMBYTES + 2); +} + +// Name: kyber_shake128_squeezeblocks +// +// Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of SHAKE128_RATE bytes each. +// Modifies the state. Can be called multiple times to keep squeezing, +// i.e., is incremental. +// +// Arguments: - [u8] output: output blocks +// - u64 nblocks: number of blocks to be squeezed (written to output) +// - keccak_state *s: in/output Keccak state +#[cfg(not(feature = "90s"))] +fn kyber_shake128_squeezeblocks( + output: &mut[u8], + nblocks: usize, + s: &mut KeccakState +) +{ + shake128_squeezeblocks(output, nblocks, s); +} + +// Name: shake256_prf +// +// Description: Usage of SHAKE256 as a PRF, concatenates secret and public input +// and then generates outlen bytes of SHAKE256 output +// +// Arguments: - [u8] output: output +// - u64 outlen: number of requested output bytes +// - const [u8] key: the key (of length KYBER_SYMBYTES) +// - const [u8] nonce: single-byte nonce (public PRF input) +#[cfg(not(feature = "90s"))] +fn shake256_prf(output: &mut[u8], outlen: usize, key: &[u8], nonce: u8) +{ + let mut extkey = [0u8; KYBER_SYMBYTES+1]; + extkey[..KYBER_SYMBYTES].copy_from_slice(key); + extkey[KYBER_SYMBYTES] = nonce; + shake256(output, outlen, &extkey, KYBER_SYMBYTES + 1); +} diff --git a/tests/kem.rs b/tests/kem.rs index e148221..c14b61c 100644 --- a/tests/kem.rs +++ b/tests/kem.rs @@ -5,7 +5,7 @@ fn keypair_encap_decap() { let mut rng = rand::thread_rng(); let keys = keypair(&mut rng); let (ct, ss1) = encapsulate(&keys.public, &mut rng).unwrap(); - let ss2 = decapsulate(&ct, &keys.secret).unwrap(); + let ss2 = decapsulate(&ct, keys.expose_secret()).unwrap(); assert_eq!(ss1, ss2); } @@ -15,7 +15,7 @@ fn keypair_encap_decap_invalid_ciphertext() { let keys = keypair(&mut rng); let (mut ct, _) = encapsulate(&keys.public, &mut rng).unwrap(); ct[..4].copy_from_slice(&[255u8;4]); - assert!(decapsulate(&ct, &keys.secret).is_err()); + assert!(decapsulate(&ct, keys.expose_secret()).is_err()); } diff --git a/tests/kex.rs b/tests/kex.rs index b4c1e62..9ce480a 100644 --- a/tests/kex.rs +++ b/tests/kex.rs @@ -8,7 +8,7 @@ fn uake_valid() { let mut bob = Uake::new(); let bob_keys = keypair(&mut rng); let client_init = alice.client_init(&bob_keys.public, &mut rng); - let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng).unwrap(); + let server_send = bob.server_receive(client_init, bob_keys.expose_secret(), &mut rng).unwrap(); alice.client_confirm(server_send).unwrap(); assert_eq!(alice.shared_secret, bob.shared_secret); } @@ -22,7 +22,7 @@ fn uake_invalid_client_init_ciphertext() { let bob_keys = keypair(&mut rng); let mut client_init = alice.client_init(&bob_keys.public, &mut rng); client_init[KYBER_PUBLICKEYBYTES..][..4].copy_from_slice(&[255u8;4]); - assert!(bob.server_receive(client_init, &bob_keys.secret, &mut rng).is_err()); + assert!(bob.server_receive(client_init, bob_keys.expose_secret(), &mut rng).is_err()); } // Corrupted public key sent to bob, detected by Alice @@ -34,7 +34,7 @@ fn uake_invalid_client_init_publickey() { let bob_keys = keypair(&mut rng); let mut client_init = alice.client_init(&bob_keys.public, &mut rng); client_init[..4].copy_from_slice(&[255u8;4]); - let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng).unwrap(); + let server_send = bob.server_receive(client_init, bob_keys.expose_secret(), &mut rng).unwrap(); assert!(alice.client_confirm(server_send).is_err()); } @@ -46,7 +46,7 @@ fn uake_invalid_server_send_ciphertext() { let mut bob = Uake::new(); let bob_keys = keypair(&mut rng); let client_init = alice.client_init(&bob_keys.public, &mut rng); - let mut server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng).unwrap(); + let mut server_send = bob.server_receive(client_init, bob_keys.expose_secret(), &mut rng).unwrap(); server_send[..4].copy_from_slice(&[255u8;4]); assert!(alice.client_confirm(server_send).is_err()); } @@ -61,8 +61,8 @@ fn ake_valid() { let alice_keys = keypair(&mut rng); let bob_keys = keypair(&mut rng); let client_init = alice.client_init(&bob_keys.public, &mut rng); - let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng).unwrap(); - let _client_confirm = alice.client_confirm(server_send, &alice_keys.secret).unwrap(); + let server_send = bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng).unwrap(); + let _client_confirm = alice.client_confirm(server_send, alice_keys.expose_secret()).unwrap(); assert_eq!(alice.shared_secret, bob.shared_secret); } @@ -75,7 +75,7 @@ fn ake_invalid_client_init_ciphertext() { let bob_keys = keypair(&mut rng); let mut client_init = alice.client_init(&bob_keys.public, &mut rng); client_init[KYBER_PUBLICKEYBYTES..][..4].copy_from_slice(&[255u8;4]); - assert!(bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng).is_err()); + assert!(bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng).is_err()); } #[test] @@ -87,8 +87,8 @@ fn ake_invalid_client_init_publickey() { let bob_keys = keypair(&mut rng); let mut client_init = alice.client_init(&bob_keys.public, &mut rng); client_init[..4].copy_from_slice(&[255u8;4]); - let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng).unwrap(); - assert!(alice.client_confirm(server_send, &alice_keys.secret).is_err()); + let server_send = bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng).unwrap(); + assert!(alice.client_confirm(server_send, &alice_keys.expose_secret()).is_err()); } #[test] @@ -99,9 +99,9 @@ fn ake_invalid_server_send_first_ciphertext() { let alice_keys = keypair(&mut rng); let bob_keys = keypair(&mut rng); let client_init = alice.client_init(&bob_keys.public, &mut rng); - let mut server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng).unwrap(); + let mut server_send = bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng).unwrap(); server_send[..4].copy_from_slice(&[255u8;4]); - assert!(alice.client_confirm(server_send, &alice_keys.secret).is_err()); + assert!(alice.client_confirm(server_send, &alice_keys.expose_secret()).is_err()); } #[test] @@ -112,7 +112,7 @@ fn ake_invalid_server_send_second_ciphertext() { let alice_keys = keypair(&mut rng); let bob_keys = keypair(&mut rng); let client_init = alice.client_init(&bob_keys.public, &mut rng); - let mut server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng).unwrap(); + let mut server_send = bob.server_receive(client_init, &alice_keys.public, bob_keys.expose_secret(), &mut rng).unwrap(); server_send[KYBER_CIPHERTEXTBYTES..][..4].copy_from_slice(&[255u8;4]); - // assert!(alice.client_confirm(server_send, &alice_keys.secret).is_err()); + // assert!(alice.client_confirm(server_send, alice_keys.expose_secret()).is_err()); } \ No newline at end of file diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh old mode 100644 new mode 100755 index f879b43..3db2efa --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -54,7 +54,7 @@ start=`date +%s` announce $TARGET LEVELS=("kyber512" "kyber768" "kyber1024") -NINES=("" "90s") +NINES=("" "90s" "90s-fixslice") for level in "${LEVELS[@]}"; do for nine in "${NINES[@]}"; do