diff --git a/Cargo.toml b/Cargo.toml index f791e85..ded4d26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cesride" -version = "0.6.1" +version = "0.7.0" edition = "2021" description = "Cryptographic primitives for use with Composable Event Streaming Representation (CESR)" license = "Apache-2.0" @@ -9,14 +9,15 @@ keywords = ["cesr", "keri", "acdc"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "~1" +anyhow = { version = "~1", features = ["backtrace"] } argon2 = "~0.5" base64 = "~0.21" blake2 = "~0.10" blake3 = "~1" chrono = { version = "~0.4", default-features = false, features = ["clock"] } +crystals-dilithium = "~1" ed25519-dalek = { version = "2.0.0-rc.2", features = ["rand_core"] } -indexmap = "~1" +indexmap = "~2" k256 = "~0.13" lazy_static = "~1" num-rational = "~0.4" @@ -32,4 +33,4 @@ zeroize = { version = "~1", features = ["derive"] } [dev-dependencies] hex-literal = "0.4.0" hex = "0.4.3" -rstest = "0.17.0" +rstest = "0.18.2" diff --git a/README.md b/README.md index e6d1ca7..6b8f6f9 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,10 @@ and terminology was carried along with the code. The basics: - `Diger` - a primitive that represents a **digest**. It has the ability to verify that an input hashes to its raw value. - `Verfer` - a primitive that represents a **public key**. It has the ability to verify signatures on data. -- `Signer` - a primitive that represents a **private key**. It has the ability to create `Sigers` and `Cigars` (signatures). -- `Siger` - an **_indexed_ signature**. This is used within KERI when there are multiple current keys associated with an identifier. +- `Signer` - a primitive that represents a **private key** seed (which in some cases is the private key itself). It has the ability to create `Sigers` and `Cigars` (signatures). +- `Siger` - an **_indexed_ signature**. This is used within KERI when there are multiple keys associated with an identifier. - `Cigar` - an **_unindexed_ signature**. -- `Salter` - a primitive that represents a **seed**. It has the ability to generate new `Signers`. +- `Salter` - a primitive for creating entropy. It has the ability to generate new `Signers`. Each primitive will have methods attached to it that permit one to generate and parse the qualified base2 or base64 representation. Common methods you'll find: @@ -224,14 +224,16 @@ Blake3 is recommended for most applications since it outperforms the other algor - Ed25519 ([ed25519-dalek](https://docs.rs/ed25519-dalek)) - Secp256k1 ([k256](https://docs.rs/k256)) - Secp256r1 ([p256](https://docs.rs/p256)) - -We have planned support for Ed448. +- CRYSTALS-Dilithium3/5 ([crystals-dilithium](https://docs.rs/crystals-dilithium)) The ECDSA curves (Secp256k1 and Secp256r1) use randomized signatures. Ed25519 is always deterministic. This means that if you need to avoid correlation and want to use Ed25519, you'll need to salt your data for every use case that you do not want correlated. ACDC, for example, takes this into account, allowing for configurable use of Ed25519 by injecting salty nonces in the data to be signed where privacy is a concern. +The `crystals-dilithium` implementation was chosen over `pqcrypto` due to superior documentation and +the fact that it was stated to be a direct port of the C code. + ## Community ### Bi-weekly Meeting diff --git a/src/core/cigar.rs b/src/core/cigar.rs index bb4af63..eaad9ea 100644 --- a/src/core/cigar.rs +++ b/src/core/cigar.rs @@ -26,6 +26,8 @@ fn validate_code(code: &str) -> Result<()> { matter::Codex::Ed25519_Sig, matter::Codex::ECDSA_256k1_Sig, matter::Codex::ECDSA_256r1_Sig, + matter::Codex::CRYSTALS_Dilithium3_Sig, + matter::Codex::CRYSTALS_Dilithium5_Sig, // matter::Codex::Ed448_Sig, ]; diff --git a/src/core/indexer/tables.rs b/src/core/indexer/tables.rs index 144b9d2..f0439c6 100644 --- a/src/core/indexer/tables.rs +++ b/src/core/indexer/tables.rs @@ -28,6 +28,10 @@ pub mod Codex { pub const ECDSA_256k1_Crt: &str = "D"; // ECDSA secp256k1 sig appears in current list. pub const ECDSA_256r1: &str = "E"; // ECDSA secp256r1 sig appears same in both lists if any. pub const ECDSA_256r1_Crt: &str = "F"; // ECDSA secp256r1 sig appears in current list. + pub const CRYSTALS_Dilithium3_Big: &str = "G"; // CRYSTALS Dilithium sig appears in both lists. + pub const CRYSTALS_Dilithium3_Big_Crt: &str = "H"; // CRYSTALS Dilithium sig appears in current list only. + pub const CRYSTALS_Dilithium5_Big: &str = "I"; // CRYSTALS Dilithium sig appears in both lists. + pub const CRYSTALS_Dilithium5_Big_Crt: &str = "J"; // CRYSTALS Dilithium sig appears in current list only. pub const Ed448: &str = "0A"; // Ed448 signature appears in both lists. pub const Ed448_Crt: &str = "0B"; // Ed448 signature appears in current list only. pub const Ed25519_Big: &str = "2A"; // Ed25519 sig appears in both lists. @@ -41,6 +45,10 @@ pub mod Codex { pub const TBD0: &str = "0z"; // Test of Var len label L=N*4 <= 4095 char quadlets includes code pub const TBD1: &str = "1z"; // Test of index sig lead 1 pub const TBD4: &str = "4z"; // Test of index sig lead 1 big + pub const CRYSTALS_Dilithium3: &str = "5AAA"; // CRYSTALS Dilithium sig appears same in both lists if any. + pub const CRYSTALS_Dilithium3_Crt: &str = "5AAB"; // CRYSTALS Dilithium sig appears in current list. + pub const CRYSTALS_Dilithium5: &str = "5AAC"; // CRYSTALS Dilithium sig appears same in both lists if any. + pub const CRYSTALS_Dilithium5_Crt: &str = "5AAD"; // CRYSTALS Dilithium sig appears in current list. } /// SigCodex is all indexed signature derivation codes @@ -53,6 +61,10 @@ pub mod SigCodex { pub const ECDSA_256k1_Crt: &str = "D"; // ECDSA secp256k1 sig appears in current list. pub const ECDSA_256r1: &str = "E"; // ECDSA secp256r1 sig appears same in both lists if any. pub const ECDSA_256r1_Crt: &str = "F"; // ECDSA secp256r1 sig appears in current list. + pub const CRYSTALS_Dilithium3_Big: &str = "G"; // CRYSTALS Dilithium sig appears in both lists. + pub const CRYSTALS_Dilithium3_Big_Crt: &str = "H"; // CRYSTALS Dilithium sig appears in current list only. + pub const CRYSTALS_Dilithium5_Big: &str = "I"; // CRYSTALS Dilithium sig appears in both lists. + pub const CRYSTALS_Dilithium5_Big_Crt: &str = "J"; // CRYSTALS Dilithium sig appears in current list only. pub const Ed448: &str = "0A"; // Ed448 signature appears in both lists. pub const Ed448_Crt: &str = "0B"; // Ed448 signature appears in current list only. pub const Ed25519_Big: &str = "2A"; // Ed25519 sig appears in both lists. @@ -63,6 +75,10 @@ pub mod SigCodex { pub const ECDSA_256r1_Big_Crt: &str = "2F"; // ECDSA secp256r1 sig appears in current list only. pub const Ed448_Big: &str = "3A"; // Ed448 signature appears in both lists. pub const Ed448_Big_Crt: &str = "3B"; // Ed448 signature appears in current list only. + pub const CRYSTALS_Dilithium3: &str = "5AAA"; // CRYSTALS Dilithium sig appears same in both lists if any. + pub const CRYSTALS_Dilithium3_Crt: &str = "5AAB"; // CRYSTALS Dilithium sig appears in current list. + pub const CRYSTALS_Dilithium5: &str = "5AAC"; // CRYSTALS Dilithium sig appears same in both lists if any. + pub const CRYSTALS_Dilithium5_Crt: &str = "5AAD"; // CRYSTALS Dilithium sig appears in current list. } /// CurrentSigCodex is codex indexed signature codes for current list. @@ -72,22 +88,30 @@ pub mod CurrentSigCodex { pub const Ed25519_Crt: &str = "B"; // Ed25519 sig appears in current list only. pub const ECDSA_256k1_Crt: &str = "D"; // ECDSA secp256k1 sig appears in current list only. pub const ECDSA_256r1_Crt: &str = "F"; // ECDSA secp256r1 sig appears in current list. + pub const CRYSTALS_Dilithium3_Big_Crt: &str = "H"; // CRYSTALS Dilithium sig appears in current list only. + pub const CRYSTALS_Dilithium5_Big_Crt: &str = "J"; // CRYSTALS Dilithium sig appears in current list only. pub const Ed448_Crt: &str = "0B"; // Ed448 signature appears in current list only. pub const Ed25519_Big_Crt: &str = "2B"; // Ed25519 sig appears in current list only. pub const ECDSA_256k1_Big_Crt: &str = "2D"; // ECDSA secp256k1 sig appears in current list only. pub const ECDSA_256r1_Big_Crt: &str = "2F"; // ECDSA secp256r1 sig appears in current list only. pub const Ed448_Big_Crt: &str = "3B"; // Ed448 signature appears in current list only. + pub const CRYSTALS_Dilithium3_Crt: &str = "5AAB"; // CRYSTALS Dilithium sig appears in current list. + pub const CRYSTALS_Dilithium5_Crt: &str = "5AAD"; // CRYSTALS Dilithium sig appears in current list. pub(crate) fn has_code(code: &str) -> bool { const CODES: &[&str] = &[ Ed25519_Crt, ECDSA_256k1_Crt, ECDSA_256r1_Crt, + CRYSTALS_Dilithium3_Crt, + CRYSTALS_Dilithium5_Crt, Ed448_Crt, Ed25519_Big_Crt, ECDSA_256k1_Big_Crt, ECDSA_256r1_Big_Crt, Ed448_Big_Crt, + CRYSTALS_Dilithium3_Big_Crt, + CRYSTALS_Dilithium5_Big_Crt, ]; CODES.contains(&code) @@ -100,21 +124,29 @@ pub mod BothSigCodex { pub const Ed25519: &str = "A"; // Ed25519 sig appears same in both lists if any. pub const ECDSA_256k1: &str = "C"; // ECDSA secp256k1 sig appears same in both lists if any. pub const ECDSA_256r1: &str = "E"; // ECDSA secp256r1 sig appears same in both lists if any. + pub const CRYSTALS_Dilithium3_Big: &str = "G"; // CRYSTALS Dilithium sig appears in both lists. + pub const CRYSTALS_Dilithium5_Big: &str = "I"; // CRYSTALS Dilithium sig appears in both lists. pub const Ed448: &str = "0A"; // Ed448 signature appears in both lists. pub const Ed25519_Big: &str = "2A"; // Ed25519 sig appears in both lists. pub const ECDSA_256k1_Big: &str = "2C"; // ECDSA secp256k1 sig appears in both lists. pub const ECDSA_256r1_Big: &str = "2E"; // ECDSA secp256r1 sig appears in both lists. pub const Ed448_Big: &str = "3A"; // Ed448 signature appears in both lists. + pub const CRYSTALS_Dilithium3: &str = "5AAA"; // CRYSTALS Dilithium sig appears same in both lists if any. + pub const CRYSTALS_Dilithium5: &str = "5AAC"; // CRYSTALS Dilithium sig appears same in both lists if any. pub(crate) fn has_code(code: &str) -> bool { const CODES: &[&str] = &[ Ed25519, ECDSA_256k1, ECDSA_256r1, + CRYSTALS_Dilithium3, + CRYSTALS_Dilithium5, Ed448, Ed25519_Big, ECDSA_256k1_Big, ECDSA_256r1_Big, + CRYSTALS_Dilithium3_Big, + CRYSTALS_Dilithium5_Big, Ed448_Big, ]; @@ -144,6 +176,10 @@ pub(crate) fn sizage(s: &str) -> Result { "D" => Sizage { hs: 1, ss: 1, os: 0, fs: 88, ls: 0 }, "E" => Sizage { hs: 1, ss: 1, os: 0, fs: 88, ls: 0 }, "F" => Sizage { hs: 1, ss: 1, os: 0, fs: 88, ls: 0 }, + "G" => Sizage { hs: 1, ss: 4, os: 2, fs: 4396, ls: 0 }, + "H" => Sizage { hs: 1, ss: 4, os: 2, fs: 4396, ls: 0 }, + "I" => Sizage { hs: 1, ss: 4, os: 2, fs: 6132, ls: 0 }, + "J" => Sizage { hs: 1, ss: 4, os: 2, fs: 6132, ls: 0 }, "0A" => Sizage { hs: 2, ss: 2, os: 1, fs: 156, ls: 0 }, "0B" => Sizage { hs: 2, ss: 2, os: 1, fs: 156, ls: 0 }, "2A" => Sizage { hs: 2, ss: 4, os: 2, fs: 92, ls: 0 }, @@ -157,6 +193,10 @@ pub(crate) fn sizage(s: &str) -> Result { "0z" => Sizage { hs: 2, ss: 2, os: 0, fs: u32::MAX, ls: 0 }, "1z" => Sizage { hs: 2, ss: 2, os: 1, fs: 76, ls: 1 }, "4z" => Sizage { hs: 2, ss: 6, os: 3, fs: 80, ls: 1 }, + "5AAA" => Sizage { hs: 4, ss: 1, os: 0, fs: 4396, ls: 0 }, + "5AAB" => Sizage { hs: 4, ss: 1, os: 0, fs: 4396, ls: 0 }, + "5AAC" => Sizage { hs: 4, ss: 1, os: 0, fs: 6132, ls: 0 }, + "5AAD" => Sizage { hs: 4, ss: 1, os: 0, fs: 6132, ls: 0 }, _ => return err!(Error::UnknownSizage(s.to_string())), }) } @@ -165,6 +205,7 @@ pub(crate) fn hardage(c: char) -> Result { match c { 'A'..='Z' | 'a'..='z' => Ok(1), '0'..='4' => Ok(2), + '5' => Ok(4), '-' => err!(Error::UnexpectedCode("count code start".to_owned())), '_' => err!(Error::UnexpectedCode("op code start".to_owned())), _ => err!(Error::UnknownHardage(c.to_string())), @@ -175,6 +216,7 @@ pub(crate) fn bardage(b: u8) -> Result { match b { b'\x00'..=b'\x33' => Ok(1), b'\x34'..=b'\x38' => Ok(2), + b'\x39' => Ok(4), b'\x3e' => err!(Error::UnexpectedCode("count code start".to_owned())), b'\x3f' => err!(Error::UnexpectedCode("op code start".to_owned())), _ => err!(Error::UnknownBardage(b.to_string())), @@ -387,6 +429,7 @@ mod test { #[case(0x36, 2)] #[case(0x37, 2)] #[case(0x38, 2)] + #[case(0x39, 4)] fn bardage(#[case] code: u8, #[case] bdg: u32) { assert_eq!(indexer::bardage(code).unwrap(), bdg); } @@ -403,6 +446,6 @@ mod test { #[test] fn unknown_bardage() { - assert!(indexer::bardage(0x39).is_err()); + assert!(indexer::bardage(0x40).is_err()); } } diff --git a/src/core/matter/mod.rs b/src/core/matter/mod.rs index 09022ad..b1a5b6a 100644 --- a/src/core/matter/mod.rs +++ b/src/core/matter/mod.rs @@ -176,6 +176,8 @@ pub trait Matter: Default { tables::Codex::ECDSA_256k1N, tables::Codex::Ed448N, tables::Codex::ECDSA_256r1N, + tables::Codex::CRYSTALS_Dilithium3N, + tables::Codex::CRYSTALS_Dilithium5N, ]; !CODES.contains(&self.code().as_str()) @@ -822,9 +824,15 @@ mod test { #[case(TestMatter::new_with_code_and_raw(matter::Codex::Ed25519, b"00000000000000000000000000000000").unwrap(), true)] #[case(TestMatter::new_with_code_and_raw(matter::Codex::ECDSA_256k1, b"000000000000000000000000000000000").unwrap(), true)] #[case(TestMatter::new_with_code_and_raw(matter::Codex::ECDSA_256r1, b"000000000000000000000000000000000").unwrap(), true)] + #[case(TestMatter::new_with_code_and_raw(matter::Codex::Ed448, &[0u8; 57]).unwrap(), true)] + #[case(TestMatter::new_with_code_and_raw(matter::Codex::CRYSTALS_Dilithium3, &[0u8; 1952]).unwrap(), true)] + #[case(TestMatter::new_with_code_and_raw(matter::Codex::CRYSTALS_Dilithium5, &[0u8; 2592]).unwrap(), true)] #[case(TestMatter::new_with_code_and_raw(matter::Codex::Ed25519N, b"00000000000000000000000000000000").unwrap(), false)] #[case(TestMatter::new_with_code_and_raw(matter::Codex::ECDSA_256k1N, b"000000000000000000000000000000000").unwrap(), false)] #[case(TestMatter::new_with_code_and_raw(matter::Codex::ECDSA_256r1N, b"000000000000000000000000000000000").unwrap(), false)] + #[case(TestMatter::new_with_code_and_raw(matter::Codex::Ed448N, &[0u8; 57]).unwrap(), false)] + #[case(TestMatter::new_with_code_and_raw(matter::Codex::CRYSTALS_Dilithium3N, &[0u8; 1952]).unwrap(), false)] + #[case(TestMatter::new_with_code_and_raw(matter::Codex::CRYSTALS_Dilithium5N, &[0u8; 2592]).unwrap(), false)] fn transferable(#[case] matter: TestMatter, #[case] result: bool) { assert_eq!(matter.transferable(), result); } diff --git a/src/core/matter/tables.rs b/src/core/matter/tables.rs index 382dcb8..dbe2b36 100644 --- a/src/core/matter/tables.rs +++ b/src/core/matter/tables.rs @@ -32,6 +32,12 @@ pub(crate) fn sizage(s: &str) -> Result { "O" => Sizage { hs: 1, ss: 0, fs: 44, ls: 0 }, "P" => Sizage { hs: 1, ss: 0, fs: 124, ls: 0 }, "Q" => Sizage { hs: 1, ss: 0, fs: 44, ls: 0 }, + "R" => Sizage { hs: 1, ss: 0, fs: 2604, ls: 0 }, + "S" => Sizage { hs: 1, ss: 0, fs: 2604, ls: 0 }, + "T" => Sizage { hs: 1, ss: 0, fs: 44, ls: 0 }, + "U" => Sizage { hs: 1, ss: 0, fs: 4392, ls: 0 }, + "V" => Sizage { hs: 1, ss: 0, fs: 44, ls: 0 }, + "W" => Sizage { hs: 1, ss: 0, fs: 6128, ls: 0 }, "0A" => Sizage { hs: 2, ss: 0, fs: 24, ls: 0 }, "0B" => Sizage { hs: 2, ss: 0, fs: 88, ls: 0 }, "0C" => Sizage { hs: 2, ss: 0, fs: 88, ls: 0 }, @@ -51,6 +57,8 @@ pub(crate) fn sizage(s: &str) -> Result { "1AAH" => Sizage { hs: 4, ss: 0, fs: 100, ls: 0 }, "1AAI" => Sizage { hs: 4, ss: 0, fs: 48, ls: 0 }, "1AAJ" => Sizage { hs: 4, ss: 0, fs: 48, ls: 0 }, + "1AAK" => Sizage { hs: 4, ss: 0, fs: 3460, ls: 0 }, + "1AAL" => Sizage { hs: 4, ss: 0, fs: 3460, ls: 0 }, "2AAA" => Sizage { hs: 4, ss: 0, fs: 8, ls: 1 }, "3AAA" => Sizage { hs: 4, ss: 0, fs: 8, ls: 2 }, "4A" => Sizage { hs: 2, ss: 2, fs: u32::MAX, ls: 0 }, @@ -121,6 +129,12 @@ pub mod Codex { pub const X25519_Private: &str = "O"; // X25519 private decryption key converted from Ed25519 pub const X25519_Cipher_Seed: &str = "P"; // X25519 124 char b64 Cipher of 44 char qb64 Seed pub const ECDSA_256r1_Seed: &str = "Q"; // ECDSA secp256r1 256 bit random Seed for private key + pub const CRYSTALS_Dilithium3N: &str = "R"; // CRYSTALS Dilithium verficiation key, non-transferable. + pub const CRYSTALS_Dilithium3: &str = "S"; // CRYSTALS Dilithium verficiation key. + pub const CRYSTALS_Dilithium3_Seed: &str = "T"; // CRYSTALS Dilithium private key seed. This one is actually a seed. + pub const CRYSTALS_Dilithium3_Sig: &str = "U"; // CRYSTALS Dilithium signature. + pub const CRYSTALS_Dilithium5_Seed: &str = "V"; // CRYSTALS Dilithium5 verification key, non-transferable. + pub const CRYSTALS_Dilithium5_Sig: &str = "W"; // CRYSTALS Dilithium5 signature. pub const Salt_128: &str = "0A"; // 128 bit random salt or 128 bit number (see Huge) pub const Ed25519_Sig: &str = "0B"; // Ed25519 signature. pub const ECDSA_256k1_Sig: &str = "0C"; // ECDSA secp256k1 signature. @@ -140,6 +154,8 @@ pub mod Codex { pub const X25519_Cipher_Salt: &str = "1AAH"; // X25519 100 char b64 Cipher of 24 char qb64 Salt pub const ECDSA_256r1N: &str = "1AAI"; // ECDSA secp256r1 verification key non-transferable, basic derivation. pub const ECDSA_256r1: &str = "1AAJ"; // ECDSA secp256r1 verification or encryption key, basic derivation + pub const CRYSTALS_Dilithium5N: &str = "1AAK"; // CRYSTALS Dilithium5 verification key, non-transferable. + pub const CRYSTALS_Dilithium5: &str = "1AAL"; // CRYSTALS Dilithium5 verification key, non-transferable. pub const TBD1: &str = "2AAA"; // Testing purposes only fixed with lead size 1 pub const TBD2: &str = "3AAA"; // Testing purposes only of fixed with lead size 2 pub const StrB64_L0: &str = "4A"; // String Base64 Only Lead Size 0 (4095 * 3 | 4) @@ -198,6 +214,8 @@ mod test { #[case("1AAH", 4, 0, 100, 0)] #[case("1AAI", 4, 0, 48, 0)] #[case("1AAJ", 4, 0, 48, 0)] + #[case("1AAK", 4, 0, 3460, 0)] + #[case("1AAL", 4, 0, 3460, 0)] #[case("2AAA", 4, 0, 8, 1)] #[case("3AAA", 4, 0, 8, 2)] #[case("4A", 2, 2, u32::MAX, 0)] diff --git a/src/core/prefixer.rs b/src/core/prefixer.rs index 0f1ba4d..3ce02df 100644 --- a/src/core/prefixer.rs +++ b/src/core/prefixer.rs @@ -29,10 +29,14 @@ fn validate_code(code: &str) -> Result<()> { matter::Codex::Ed25519N, matter::Codex::ECDSA_256k1N, matter::Codex::ECDSA_256r1N, + matter::Codex::CRYSTALS_Dilithium3N, + matter::Codex::CRYSTALS_Dilithium5N, // transferable matter::Codex::Ed25519, matter::Codex::ECDSA_256k1, matter::Codex::ECDSA_256r1, + matter::Codex::CRYSTALS_Dilithium3, + matter::Codex::CRYSTALS_Dilithium5, // digests matter::Codex::Blake3_256, matter::Codex::Blake3_512, diff --git a/src/core/siger.rs b/src/core/siger.rs index 516f6ae..5caf298 100644 --- a/src/core/siger.rs +++ b/src/core/siger.rs @@ -31,6 +31,10 @@ fn validate_code(code: &str) -> Result<()> { indexer::Codex::ECDSA_256k1_Crt, indexer::Codex::ECDSA_256r1, indexer::Codex::ECDSA_256r1_Crt, + indexer::Codex::CRYSTALS_Dilithium3, + indexer::Codex::CRYSTALS_Dilithium3_Crt, + indexer::Codex::CRYSTALS_Dilithium5, + indexer::Codex::CRYSTALS_Dilithium5_Crt, // indexer::Codex::Ed448, // indexer::Codex::Ed448_Crt, indexer::Codex::Ed25519_Big, @@ -39,6 +43,10 @@ fn validate_code(code: &str) -> Result<()> { indexer::Codex::ECDSA_256k1_Big_Crt, indexer::Codex::ECDSA_256r1_Big, indexer::Codex::ECDSA_256r1_Big_Crt, + indexer::Codex::CRYSTALS_Dilithium3_Big, + indexer::Codex::CRYSTALS_Dilithium3_Big_Crt, + indexer::Codex::CRYSTALS_Dilithium5_Big, + indexer::Codex::CRYSTALS_Dilithium5_Big_Crt, // indexer::Codex::Ed448_Big, // indexer::Codex::Ed448_Big_Crt, ]; @@ -252,6 +260,13 @@ mod test { .is_ok()); } + #[test] + fn new_with_qb64() { + let qsig64 = "5AAAAKEWfy8izZF5MNOHRA5jj0WdWR4LnasWt97UTwEgku7o5xd_L7Oftt8oHAS4qO4gUpbj7rZntpI4wB-vHSvTXDBXSsEc3NOJ4Vb1MWfxiYHsJSSHSh5g-_S-6LmBeC5v66eMh8RUsAuP-SqfXwH3O2Vim3e44wTY7tf5XCxuGHdXLpvksZ3ut5W-TtT_yz5zCzO88M4SwNKg6VACGXwXyASLzlsHSaxx3Y4FQa8o3AImkfoIJmMQYHYo--EhIJkWl5zLOmljGenQUC7mie2wqe0_JtA0PS-2lsFRFhHT4xvoHDNH-T9t72mZY_fHqeuQx2sqf6f-tjqAzSly1DHxPc_q6evDLSev_90GGWmaY2ZcionQZZr8pM741vy7u_pdSRc_rvrEcSf9ofE_4eXFezNHfHBVlsLaX3BsztwXvAxT_FmCRrrTGzR_uYffYnAdvaLCDdnuflaEC8stAsuOEnZbpgHIeeYWJK8xkwq-pwDQ-khGFVM0aJnMUIyNJpHzwBQS-OcTjU3HLObOOy5L3tuTkoRdvlxv0nNUre9ZY5S7rDW8vSQgCEXJOw0RkKr5uOjwQwM-yARGu-Ta44RddAKDvijDI0OAyT5Lv2U2U1ip9y9bMCOOr4dRK3elOQ6M0RReAfLb6UFniSqbfevFyJ0WbfNfDaqhhbo2J2V0Ck53kb1G6pY7yV9BNlBrlvXQARedf-wLgby3jU0Y06yoCWdavycH9-vvAKzBF6ggnfxJCeJNnAIATy3dfvsBaYRv4uOa6gODaSJuOdKAInErMcGUi279jTUy1LtPk9v1LMdWoTm_zT-K3kwvEu1uU0kcszzVjJUOAl7rDbXeux1CyooyN0MfH4dtUgUiSWGDq3JoNsDSEuQ2XfztoNQcS82hsRzgQsyvTeXsSqp92MpO4jCfGv3pvhyAUdv0TKh1wkxXvj9P1Hv9WmeSFpYCx1aZlqekYcKedPEZ2jDAVJSFsJUVGvyl8_meOZvOCUSTAEbjoL52tdQu8wUmreRBRyrfXkh5C9a3Jl39YHSkhStc1dgwHOJmLFK3oGMRRlwnqlazQ77JjIFJYjt2i4q-KfKDiIURL6ai66fTHXbndvBMq548NVcQYrfIOI_xRnKEXsDwEGMJhc47Fmk3sznpJ76yIzCXchqepmLXbBqM6sA3Gwd9dJZGzaJwpSeugEBZmjckU7rwzyDXim1sphs2ywFKGMyQGxvUOv7HgriPpbR5kvuSNN_HXDZaAzatWM-bbcfvv-3WxAmY398SSaQpe0sWaa9IxAhbCUB1jgPxslJLNNLfWF8J8vp90SxMRhlwZUGZGclSvlM0plFYrpmeqvNlhr3iViCquSQDDQmD4gqE2lViKA4PU7TxYPb1Ywiov0-bjlQylTckf8dkI3ZafQgNNpOCdquj-8AkGoUzlGHx1sg-hxSe9XphO8a5Gqd204ydiNzHLr1CLBDdkHSwcDA6j2UHlrfRV8mtM1Tfcutl05ise_BQgv5C2EiYw-r_Zz0itQPngCH_LdVT1NBTlPyPy8DxjGnMjwthaOhBBc8mSoA4Xe9vz4cWhjJ-UJaCtESUz7zybMJ2toafTrtBptE0TjZFWC1oZBCEn1codNMQ1fIzddCPJpce8NvvdZrEkqP0UT1RuxR35-o7aVOtWzf6WtpvKre2doKliwgNnMXOJHUZdAWYLsolPW5wbkCElkvQ0vS0nep_jFJuDt3AvQdkLOhf-wRNSiswCz8-LNWRNVZV2bdJ90CiF4jr-L9jb4Tzt38oJM1xXSgBsn0XErcui0GZPm1R80pM3kbErebrXn5XFR6CoKqgHgCf_X2kQ5nQHtir5ipskq35kEG7pZ9vRaSw6YBqz28_eUHITN0PfNHIGSAo8shsqCuV8DdN59iBLPKr9JvZK3FmzOPsLGNKcmYS0UMVSbkCSfRMb-s2jKOqFbSe4xsFCky90CcNsxUIqBIRhNu5f2Ebqv7jZOVR8wb22j3eNBz1Mp1Jpe-asxD3o6O0gbIGa081eiMoKUvG60ZRfVwroKd0OP-LVKPP2HRB6UHGyMZ-MxYBHhLbc_3un5uvTIgQ-2i2fzLP2Az5vMY12hTbYqzIwWVHa0O2nzdTBAzM7fSkupSazxG_24Th5HF5RTCJAl11KsPPzKbimFdE1yT7S9lGIDGk446fYdhdGhUs_ujiowlNZkDlaxk_L5zymDOwRUfYYwfpIiRVWhT6OgkS8KaqufHIBowAN7WQIeQ4RTYsJCF5wYUGRwB_dvLyJehXZlilBIXVLeL5kMbYTMMuF0QZbKDVymAAXI6m_0LLEsCWbLoOjWvz8L9QvNWjFiEZzGOMZa1g7BTQ17GFJ5aOWJ0tvaAbIS079zSOj0JFF889AxuRF2UizQCvXeh_geSQ3ccgWBwpSv6Un85GdTiQUQKcZRSOtNT2-pc6mCj6z1vKFr0zwktY4B5JYMw-mbHlq8KUz_rBwVU09MhuCRG-eqv78PCZI0Lg6jHXpgjTBR8Z3ylH_eU4lQxH_8Qm8_4S2IoHHnMa-EXiNaxoxPT3GJOCjNvXVKAbVKfnmau32R2J3nBYwShSfGh32adA70JbO69D_zHIAkJPdmr_ZTUh8RYzVtetHLNO6wHGhat-Kft6k4rSmN-epMzU80pgp_e22AfXS8YhyuE3JOT2C6H5VC1eO6jO1ra3njqHGtQpTcaXRELCHZBS97bykJP3Vpg93VY1kFZEgVY1uGiXrCLI-PTPOJUEWv9GR7x4yesfyOboQPrDsCoLJgXd6DMPa_L2xbCyz-fuqzsJm_6sjzjXGx_MJXlOLAI9mw4JEUUu1xM5rqkxHiQ8_RzTBxfmA2kNYSsPRJDuzdWcI7aLXS1w6JC7Rfmb5iYN15Sh2ykgCZdU9o_fYc49bnS-Eyqlt5-C_ZY3vx2ipspVjBnZZB3fnenAfpw9JJvHVhpCFIdIU1W_QiZD5RrFAK8sw8MXIBlSTc6yfkRx6FiZ64ih17g7_VeYmZDjEndl7MZNxq5o3fbLiqIAFrV_KIqQqpUu-wSYtqKSXTaaVAb8QsVjh4ab9vUYkiW9hoU11O0SvVGajD4fzejELhEFBZsXfz9DYrBGGukeEEU-BIawpv-CCZAl5e4xbHaVPg8OvyIHf9uF4OlEodY487Bji8oP9qpd5YoYbbbUfiCIrxWfcR9DnXZAnJmj5Cjr9shkIsqXjF5ra3qWjMfcZh7eS0vRWpioL9EHsHvncodGFO-sXCiRo70SOmQPtKc4R5HHFw1c9Sm4etqAHqMHXMcZYbnrhaFQuJSnL4fe5wVJLEmvcPFueA1Ymz4tOlxjgzC8VxsWnFRCBYdLnxTvHeMp18h5r8kWz3Y0auhxzLHSR4cOirgKWNCBSSZvgvzWYHGLtDkiPoIfOJYZ8pqbKzFyRIqvkZvBQwBXHmyRyz0_pxkoeGIP0FaWGu0YBLy-y6ZEzNs0igbisX8-DtJ6ORrnsFGVaYEwVnPFlPydJ5n6r7geEQR9ZxdXXzG2VBaY4OJwHr5_WP4YmiPxdQWaJPrC6xZHthq5el4j82exKwXU6VXduhPY7n0n1TkIY9-i7jxRdkMI_RIlXylrNYTl_L5THA4NIgmoBJFHyDeV7tHwQPTvoz-AQe5TznzS4oMEfYY6HBBjlqXkSI0sySPC3p0QZU7oMQ18gGQDpqagGJYRr4OpJFvjcvEa2KEUmqkz-cfo2WFq-jjxO6nyvR0BQrqXE_L8Du63qj19yYEF4jX2HRvAQSSw20GqjaG7Ua0WM4fRGU0MIZ996j38iJdSAlsA9vRkoZNj_V-SQb2sGkN1qUyZK9YuhQ8BRdLs-ksxnJjLTAur4UpyWncYUeegj7PmSSv2MPe1B-6IKhlqr3vzo8S3K8xteGXR6LMhsh_mU0Bbo_HLlIll_xNcCh-HgGkLb-sqKcC09HwBEGBB1A3xO_rNkIjMcgwClA-l-3klQCohmkk2fd39m_ZYq5MabS9ge2jV8jg_9jBJVwO3kd9KhCRBoYjnGucN2eiheo2BsFFrFo7lexE7z90Pf4zhLBu-RKqV4X0Y7SVUWZgJBNK_GAmyAWmqYMmviO0fP5UZ29KoDdIpgnCqWme6FNTyew7wFvL7pbeEr7OcGzH6zDMHQdNFPns3MNCw6OMUIq2CDSHpccaj2vZkA0gM8z8Tg1MdreU12UkyzVjFFFkdCROSX32hBndzQa14977XP1JBom_vlzFdDxOeZ03-cVTpzH_Y8ha5D9J_gKA9locHSdbvUA7hAzjfrVVpBAAHpc9prqqO3bLgt08dCLa9Hf08l9wzyBQCW3_2ETRq0114g6Ws2uouS1S77_MNb8AOD1NVWGBoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgPFRgf"; + + assert!(Siger::new(None, None, None, None, None, None, Some(qsig64), None).is_ok()); + } + #[test] fn new_with_qb64b() { let verfer_raw = hex!("0123456789abcdef00001111222233334444555566667777888899990000aaaa"); diff --git a/src/core/signer.rs b/src/core/signer.rs index ce44db3..e1eae57 100644 --- a/src/core/signer.rs +++ b/src/core/signer.rs @@ -61,6 +61,8 @@ fn validate_code(code: &str) -> Result<()> { matter::Codex::Ed25519_Seed, matter::Codex::ECDSA_256k1_Seed, matter::Codex::ECDSA_256r1_Seed, + matter::Codex::CRYSTALS_Dilithium3_Seed, + matter::Codex::CRYSTALS_Dilithium5_Seed, // matter::Codex::Ed448_Seed, ]; @@ -77,12 +79,16 @@ fn derive_verfer(code: &str, private_key: &[u8], transferable: bool) -> Result matter::Codex::Ed25519, matter::Codex::ECDSA_256k1_Seed => matter::Codex::ECDSA_256k1, matter::Codex::ECDSA_256r1_Seed => matter::Codex::ECDSA_256r1, + matter::Codex::CRYSTALS_Dilithium3_Seed => matter::Codex::CRYSTALS_Dilithium3, + matter::Codex::CRYSTALS_Dilithium5_Seed => matter::Codex::CRYSTALS_Dilithium5, _ => return err!(Error::UnexpectedCode(code.to_string())), }, false => match code { matter::Codex::Ed25519_Seed => matter::Codex::Ed25519N, matter::Codex::ECDSA_256k1_Seed => matter::Codex::ECDSA_256k1N, matter::Codex::ECDSA_256r1_Seed => matter::Codex::ECDSA_256r1N, + matter::Codex::CRYSTALS_Dilithium3_Seed => matter::Codex::CRYSTALS_Dilithium3N, + matter::Codex::CRYSTALS_Dilithium5_Seed => matter::Codex::CRYSTALS_Dilithium5N, _ => return err!(Error::UnexpectedCode(code.to_string())), }, }; @@ -148,6 +154,8 @@ impl Signer { matter::Codex::Ed25519_Seed => matter::Codex::Ed25519_Sig, matter::Codex::ECDSA_256k1_Seed => matter::Codex::ECDSA_256k1_Sig, matter::Codex::ECDSA_256r1_Seed => matter::Codex::ECDSA_256r1_Sig, + matter::Codex::CRYSTALS_Dilithium3_Seed => matter::Codex::CRYSTALS_Dilithium3_Sig, + matter::Codex::CRYSTALS_Dilithium5_Seed => matter::Codex::CRYSTALS_Dilithium5_Sig, _ => return err!(Error::UnexpectedCode(self.code())), }; @@ -169,6 +177,12 @@ impl Signer { matter::Codex::Ed25519_Seed => indexer::Codex::Ed25519_Crt, matter::Codex::ECDSA_256k1_Seed => indexer::Codex::ECDSA_256k1_Crt, matter::Codex::ECDSA_256r1_Seed => indexer::Codex::ECDSA_256r1_Crt, + matter::Codex::CRYSTALS_Dilithium3_Seed => { + indexer::Codex::CRYSTALS_Dilithium3_Crt + } + matter::Codex::CRYSTALS_Dilithium5_Seed => { + indexer::Codex::CRYSTALS_Dilithium5_Crt + } _ => return err!(Error::UnexpectedCode(self.code())), } } else { @@ -176,6 +190,12 @@ impl Signer { matter::Codex::Ed25519_Seed => indexer::Codex::Ed25519_Big_Crt, matter::Codex::ECDSA_256k1_Seed => indexer::Codex::ECDSA_256k1_Big_Crt, matter::Codex::ECDSA_256r1_Seed => indexer::Codex::ECDSA_256r1_Big_Crt, + matter::Codex::CRYSTALS_Dilithium3_Seed => { + indexer::Codex::CRYSTALS_Dilithium3_Big_Crt + } + matter::Codex::CRYSTALS_Dilithium5_Seed => { + indexer::Codex::CRYSTALS_Dilithium5_Big_Crt + } _ => return err!(Error::UnexpectedCode(self.code())), } }; @@ -189,6 +209,8 @@ impl Signer { matter::Codex::Ed25519_Seed => indexer::Codex::Ed25519, matter::Codex::ECDSA_256k1_Seed => indexer::Codex::ECDSA_256k1, matter::Codex::ECDSA_256r1_Seed => indexer::Codex::ECDSA_256r1, + matter::Codex::CRYSTALS_Dilithium3_Seed => indexer::Codex::CRYSTALS_Dilithium3, + matter::Codex::CRYSTALS_Dilithium5_Seed => indexer::Codex::CRYSTALS_Dilithium5, _ => return err!(Error::UnexpectedCode(self.code())), } } else { @@ -196,6 +218,12 @@ impl Signer { matter::Codex::Ed25519_Seed => indexer::Codex::Ed25519_Big, matter::Codex::ECDSA_256k1_Seed => indexer::Codex::ECDSA_256k1_Big, matter::Codex::ECDSA_256r1_Seed => indexer::Codex::ECDSA_256r1_Big, + matter::Codex::CRYSTALS_Dilithium3_Seed => { + indexer::Codex::CRYSTALS_Dilithium3_Big + } + matter::Codex::CRYSTALS_Dilithium5_Seed => { + indexer::Codex::CRYSTALS_Dilithium5_Big + } _ => return err!(Error::UnexpectedCode(self.code())), } }; @@ -309,6 +337,18 @@ mod test { "QJ97qKeoQzmWJvqxmeuqIMQbRxHErlNBUsm9BJ2FKX6T", "1AAJA3cK_P2CDlh-_EMFPvyqTPI1POkw-dr14DANx5JEXDCZ" )] + #[case( + matter::Codex::CRYSTALS_Dilithium3_Seed, + matter::Codex::CRYSTALS_Dilithium3, + "TJ97qKeoQzmWJvqxmeuqIMQbRxHErlNBUsm9BJ2FKX6T", + "SFXIJIfr7VJTb6AV6A-zZfinSBo7NlZkeffGOL2a4jbeuLU4SIqchhoT6PuAL1SP-Izi84lJDEP7wmU3L6iess2gvI6nGWn0QYGWoOh2fXC4ZXRqqbQcVlqfUL_VH0vGLpYxPQEljaHPtxtZO1vVUHyburUjmZ6d3YzGxJ2G3L1sGjveFiwGO_vV7tC12Fs4F_2Qtq2oybIn5FrCPPns-MrRXSKM3VgXSHzrUYbmAwmufLlW3IfQPsIWPMzfA0sFk5wuD6tBVIw5nGme2D0SjjY8kg5McYxScZX_Oe6tS6dXXAJ4ibk3xv0VeQRGOfTgViM_GANIJ5OTcWS-Rwe60_i95hYJG9F-fQ2jt8Y2bYqI-ELTQeozF5PnkcMm1Z3PCnRxdfgrVuAmxVxWR8to1yPMHVKw9Uzn-nK5P7y1Z_VYn1jdfdHq4YnrVNmZn_F9g4CyTNqEYY3j8HUXFP9Dax3-XhHYqMnL4tJ6pUMaDLmqQ7LVCr8V-VQN9WTRIIHuhF5ixnVI94LV8FeSinFv-UEPqnVQ3aTvCpRdQV4uhvXu7DA_hata6R_TYJB2iGJyij9PhZDBTs2gDR0EQ5qFGFXqtp_FE-YYVT8dx3PpINTvTSGoPBpj6KraGaFKuuamJHZN2PlRR9zV8eSGwzA0I-8TlAtC5YePGMWJEPsc3dOzGcktfuPQn3tMka3LuYxZ9NaoHc3iRWZnXN-KnhRf31JSuVQWxmhB4pCd5L46AdwXapL5SFiJhkvV9LKiqzsbOLThCocuRLdGOrLFDnrBkxnit6_sbpV7fRVJYshu2sZ2u4TDjAj4XgM4tR7tkgD9pNqhtdMaqeS9E3aKcTNldDe11vRlT5tEOlcD6w9VrAzRO2V0sqZdKopzeS_QWohUxZYlF3QKuJ6Vd30GuvOa2za9EQdwLhWVoJHYl5vU6yerDEloTnX_AZFGxzqQEK0Pc31R5rU9s9OjZrcRPn19XI0BmfphrCMxv_eTThHPtlLS5AE7wzQEfk1mhjPzXh1lbDA0L7l846fI8EvWfpyTsniOubBZLHGFzOheZoOlJsyjPcs-9eFEgRGdGvwELkA_qlqb16V7aBJ27MZ22aYl2dMGcBGqObnwdJS055ZYS_gG4Skl6Valse9w95npfNmfu5TgoqUqdC8FV86vV4wR-mwagHKsrahKMIpjpmH7pobNQm8G9hU_ZpTd_VhIwObaMfmNMwTEWufzgYB7ouUF_Z6gkm0xJkVZ0LXfmL2cpF4zljej2vcNcbNNlKqM4GgYvDpV67niDooXqycGOrF_VH_OQUnew0r1An8TvOPKH_HiiD6YJtHUTEa-5mdouVlN9SHBGPkwm3JSqHW_Cmtir1qrV_lNyYOPwaYzgME-alkizNrzY7mA1iTzl0sdUHcLXq92ej9Dy0RY7C4bmlNzO0LYlpFk8szpx5h3kAKjq-E7qg8pwyMs6Bg_G6qrbJyFMo4mzVq8OvdTYJToMi626S1SH5LQPMzUP9wF3sSlsulpFXXFFcOtlMgSSYv-g1JuqV6euFyqW7tNL5IboLtOrZkBQBCzJj4w1pkl5IUVfHpGXauv-WkrHsUbpMeZAPHNUJbRbki8U7Lh9mrXriiglFelQO89KO5CICLfve6sydk20szrNh7RQZWL1X9eE1VIhaiOIUkoKn9mPmcpZfNFXlj67f1Dhc9OLRGOmcEaWZNJ1rCMJET3_MZnintbsWycKVcrGRidqly8KmxN8DB27_N73Ei1ejSmE2LNJCtcAoD-LWtpu0UTrZ9exH3U_dsJwUZAcywqzJLvBDTZE53GRq-taP1pfGBB_1gaSkO_CAHz0xZtuJyZzS3T8C_ZXgGEL1wuSiYZJXMf7Vw2W-6drRXt63sdrz5nk2THiS9kmn9gQkIO7319fIXOToNpCO6cROOT_rQkv4ZClIdoAER-eWS-aP0wHvDcgSlroeZjRk_qApD34yWtNNBexWE6wyoL6HEI7kxHJbcQ_Zsxjnb8bOTdHJ-weZLMPAGHVzyTJSrDqYvxsBJuCGnjTE44Tw8FjKGM_rJaqOygJjTpHwTOjYQdo-bDjbDaNxwcQCpOUeic_QwxXbB2MP7PJahRU-NhGLYWCS3yh8aVslNcgmMto7juVCSKtrp3GCOwK-gB0Ay4_A0bly33LbadQTuw10QrkD_pIWigYAeD_FYcjixcmn382vRe6yWJBUtPaiwFjQ9fJ0icYZcrHCfZsDMa-lkyld3rRKZv7UFiTJdtUgRg-UCo7inQoK6lW-wFCwVD5lwjWpda1HHn-8uFje9or533XRlEezKEofEAGy6WTd9pttaVyxyq1buagnUGSEf7fxf6AObpFzzQt01WVl5bQCf1SdoUfw5yqKe7xKmsfqUmsIoX1AfMdM9Iyy4TGuz5y-uWWxv0hbrsVIzrPpnxc_h_IRksfxeuGCXFx-sSIb0lj7cqdPCs2PbJxp0opbw6qKCbafOXzKrqhnCTUbjfaYuwN4PNOnWYIhelI327jTNiDk3GoRn0lBjx75ACBGeGbE1qiI55bMCJjDhRwmfsDtpd83cN7isFJo6djOlN_WjytOVAm8b2m-QXp2kUlNDcwZcw" + )] + #[case( + matter::Codex::CRYSTALS_Dilithium5_Seed, + matter::Codex::CRYSTALS_Dilithium5, + "VJ97qKeoQzmWJvqxmeuqIMQbRxHErlNBUsm9BJ2FKX6T", + "1AALVcgkh-vtUlNvoBXoD7Nl-KdIGjs2VmR598Y4vZriNt7g2O87ZrV3qe_3Rptf5a99SlayG6VYUBco1stFt-OCNizwaB4p5lJiwshSyvyUP64Wp1LwyEc2IJ2lLVwWVTycAWAUnawzszVUNOOOAGRWkfJCv5Wu1lph5sakb42EORBJ6ePoy3ZCwj2rGWIF75jkU6yMHsR0u8glhT8GnCrCALm93AYlk6bj_vUq105dM6fWFw-AvgO9MCh-5uZ9kVJ2XZzw7cVXIQ5b365GhZj9nRF1AeKYBk3nijvxcv73qX-YJCAH2Br__TnnpOXEPiAfFqVbPDZENf9vDo63b0rjWIPFXFMiR-_XPhcPAJ_z40abFOBc8eZxlM1eYImmoXJ4n_cyrB95Ajc-wqG5xLet0qVSAzhe447GumSHsfeRE6LZ7coFCuAEN5ihZ1gAvLj2HQ7IProBIcRE41FLCjB2AIKFyr4pWc9WUvmw-bqbV7LPPmWw3-g9hGO-5hX92GJHsUV3N_dkSP4iLomG98vaRcUKtKoo5i9nYtRN1arsIFzydHCabn3_yoYYtLw54HZn7-vZdC_dx5tFclySmtmYao2MOLMlt3aBDMSEjXirNzdYX1QZkTvDp8huWCi_rV2_K9HOpBkFPjentqM8bBTMs2MkMmRpJVKfUux4HlneJ4zFC7Pnq-a210ldfOnypjGrAdrbt42pGbaKtLlxrpEILouAIHWpiVideRboBH0HBdxknrwaGi3zrgPwv-yRDaO2qPtYIulr4xLW7m7BEf56mtjbGd3yAFPphT9x5igdXzG97G-b06WHKElDGe_VaxzDr43gSlky0ELH_JcMRZjZUwpMzjh9j99rRjn4vQzdlI-oTS7Kw7p4-PHHoeMlEzzJCOGzVhlgnebUD8FRV4Khg-M9n5t52AYR7GGeGOHu45_pcE0ud2ZbKAyaUs4f2XlwzxDLBHMtbSy0t-8EmwQvC7-AlOvw0iUbKrXrYKjzMdImvj3lDktb-WaHcsczOC2mnDs8qSYUE0J1dxsjdaHrDnAt6HksawSHzsK0svThdgxNhWo96trJEOcMJDgmMft1nboFUIW5vivqxn9TdXPrSjTSgcH6Yk4T5ZeoP_C7EDaj-_F62_Da5lAe0XuLk__Zq-AlaDdl7W1_Jxuex1w6La9wYIDg1yuCa6ZOaTPKFwKn9ygsraAhdTpK3vAJeLYZxx7LAAgL0q68pxh2Mprw-fxnjeSqXMCOwPf12fYeHK9Wyul96pXQGHh11ApRs26ocLb8s2P3wEbgkMoViiQVhsAkd3ySQJsZNnOAWMtA5GkCOw2zmc8bMTl3b0CBPeuhPRT_8W5W88xTPP5fP60Pm4Kd3pr6_GF1JC62hQkHrQv53jfUcqNA8FAFWP9Oxa1GgOWZiDuP0TtegKQqcmEtadkXju64iXMPa7R3RzKpyq-ExAPtoT6lr8GCNk55zgyKY97gt4Pxe8bnp8oI7bNdwX8QmwdF8EaQh_T2ABLUFlDmCi1gxB6urytf24YZ5sgyDme_u4goNWj6TBSoDyrhIxzNHq5GRxsB62pnDmoCRlEKfwoUTs4LKLD-sHHujOW-8xeHGmlDME6UNSwYq1W5zKp6uQbWcgkANeFYsE5zPavnUUpsFf7DZWHQaFzcvI6pgoO0mkHhKNXg2F43bK6CkREM7BdKb1GxtYEabt0BxfuP2A02ueES8TGl6MghKFkyt-Ju7oM6WDvUAYDJDWEfKPYELBiaOlT5ZN3XMpvcBFVcKzRD9WZODx2KUpV1_uMf7jSYkrwbHF3JP52ogaRaMqaPhYFS_R16D-KpBOWr5tccnOv-hAyHet5Fd-Yjjp2YFWHNgEf3iP709tjfxsfq3l1hRakSfYk1ImOtcuc8LdLm4xgIg0s1z1lp4tdd7CxlxBBqS_GmV8B-cl4bIiuQ6cG7EftegzaCnHiQgCGOa8wtrWoKXtY7aIhRb8lu2Od2bKm-4A8RTXyC9ScWZeb54VINZxV5eLpYywy9wg3hzjRuYnHsVJJx8Jm-PviPutyoSOvJc-f6xc9WwAkHVJQRmaLdrIX2u76CR_EzTsxlw0kz3ttwFNrql7z6UyXRBkxkmu9g3m8vpnafGKiqoH3yKZ4FBThHjWdALJUabWJFqO_0X1lJIixtEu8eESBazgPbYw0kEpfyoDvOSDaZ-xDRKTymRYV2qp3E708P5TvjPFS8heysGmqQbZkjAa5j69j1hK0dN4-sPHHPgMlqNqTuNWZMgh3LhISCf9DjIvJjt-xc1stDCvCfmU7gpmUfw8di5WbTuGGnGMPXSNjGnh1DnVSL88jPwp1yj1KqPiWx9QMLjR3Wq6XhZQuVuvzwtvusZJqyw0D-DfITzMFGYuXrUQU0KbO5jaPonMTn2B6i0kOi6gzmlBRT0oXjw1fp--Fcnppfzy9BBF6QiNQgG321Pq0M3NfPNw4VLoZvwcuh31RKDUhcuWOstXNGlKwNw1ShtxWx3ZgbYwSzGNUldwVAPMqlV5sn4c4wUCkGfFN55EQu5PTFFfSDIshBdieOMY1giriw61qd1bsQJ88hUGz0VQH0AdKgyXyd9xIfWHsP8dkLnU3wZGoD58nazCAO1RRNPMjmwEVAroxWQF7nGuYI8Ipmf5quxp_nGkhGuUiCVClpgFBUydDdSnukF6zuDdSLCIlLB3K5lzeo4jhhrT5uhVdbtFx5dNMDHemq1YiLntNH8affPhhFHk6SqAXsfBiZ84TRXmlL_kwfO4EfirlMalMmF1HzO1ZG6Mls2e8q5c13nIWzsayWsM8902X_o8XdMdN8OgjkG-OlA0BRweJ0m_whrAU7_zLSPmS0MPPB9vP7kS-CS4LdJKgScs9fqg41rdNfhzcDytmQ3rDT2bgb63xgxUuQaBQiuiUWSkrFSz3KXUUEWGtrKnYzH-q7lTyXPbSIperDy4Ap_I1P1yvG1IRF795j-ebXNE6hd_t6PzlPCO1xgzvubYtBd8MrEEBNwtUoPwHNc_9S35f4ia3O4ka34OGrkLOXuVvvre6hmpsZ_-JJMFkAP3DkKgFP6y2mkGcfBgy6IRL_-QPNh7ONKBAis4NWv3oQUQAVAuJn0nXUrU6uu9u4mwczbpAeP-IF29ebuMFwDBaQ6fZi43vx19TijkSxajrHpxEW4nifuuvsjsEeM6YfOU4OhF39CWCzNYLd0Y0KFCbiPe192nIbUGtVPUj3cbxdswfm0kzA0awVVYw5lP50ch9Ri2_lrh6n1gN-YaZyODQGV734Wge-OPzOmwW3f-9gUBxPPp8ZyMu8ZLFaYNkVVMDYOH3YDxokq90i_NMny2iqTvhWmD5mxs1h_eqiS8pXdFhnrCO3dR2W4yQW-soMn8-H4P1ls1SlwxJg_X1wJwalh6lV1Ocp1szSxltLuYIWSS9jQzhcNpO6pLSkKSOWZCHz6PgCnCJ4" + )] fn hardcoded( #[case] signer_code: &str, #[case] verfer_code: &str, @@ -410,7 +450,9 @@ mod test { #[values( matter::Codex::Ed25519_Seed, matter::Codex::ECDSA_256k1_Seed, - matter::Codex::ECDSA_256r1_Seed + matter::Codex::ECDSA_256r1_Seed, + matter::Codex::CRYSTALS_Dilithium3_Seed, + matter::Codex::CRYSTALS_Dilithium5_Seed )] code: &str, ) { @@ -485,6 +527,48 @@ mod test { assert!(!signer.verfer().verify(&cigar.raw(), bad_ser).unwrap()); } + #[test] + fn sign_crystals_dilithium3_unindexed() { + let ser = b"abcdefghijklmnopqrstuvwxyz0123456789"; + let bad_ser = b"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG"; + + let signer = Signer::new( + Some(true), + Some(matter::Codex::CRYSTALS_Dilithium3_Seed), + None, + None, + None, + None, + ) + .unwrap(); + + let cigar = signer.sign_unindexed(ser).unwrap(); + assert_eq!(cigar.code(), matter::Codex::CRYSTALS_Dilithium3_Sig); + assert!(signer.verfer().verify(&cigar.raw(), ser).unwrap()); + assert!(!signer.verfer().verify(&cigar.raw(), bad_ser).unwrap()); + } + + #[test] + fn sign_crystals_dilithium5_unindexed() { + let ser = b"abcdefghijklmnopqrstuvwxyz0123456789"; + let bad_ser = b"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG"; + + let signer = Signer::new( + Some(true), + Some(matter::Codex::CRYSTALS_Dilithium5_Seed), + None, + None, + None, + None, + ) + .unwrap(); + + let cigar = signer.sign_unindexed(ser).unwrap(); + assert_eq!(cigar.code(), matter::Codex::CRYSTALS_Dilithium5_Sig); + assert!(signer.verfer().verify(&cigar.raw(), ser).unwrap()); + assert!(!signer.verfer().verify(&cigar.raw(), bad_ser).unwrap()); + } + #[rstest] #[case(false, 0, None, 0, indexer::Codex::Ed25519)] #[case(false, 1, None, 1, indexer::Codex::Ed25519)] @@ -593,6 +677,82 @@ mod test { assert!(!signer.verfer().verify(&siger.raw(), bad_ser).unwrap()); } + #[rstest] + #[case(false, 0, None, 0, indexer::Codex::CRYSTALS_Dilithium3)] + #[case(false, 1, None, 1, indexer::Codex::CRYSTALS_Dilithium3)] + #[case(false, 1, Some(3), 3, indexer::Codex::CRYSTALS_Dilithium3_Big)] + #[case(false, 67, Some(3), 3, indexer::Codex::CRYSTALS_Dilithium3_Big)] + #[case(false, 67, Some(67), 67, indexer::Codex::CRYSTALS_Dilithium3_Big)] + #[case(true, 4, None, 0, indexer::Codex::CRYSTALS_Dilithium3_Crt)] + #[case(true, 4, Some(6), 0, indexer::Codex::CRYSTALS_Dilithium3_Crt)] + #[case(true, 65, None, 0, indexer::Codex::CRYSTALS_Dilithium3_Big_Crt)] + #[case(true, 65, Some(67), 0, indexer::Codex::CRYSTALS_Dilithium3_Big_Crt)] + fn sign_crystals_dilithium3_indexed( + #[case] only: bool, + #[case] index: u32, + #[case] input_ondex: Option, + #[case] output_ondex: u32, + #[case] siger_code: &str, + ) { + let ser = b"abcdefghijklmnopqrstuvwxyz0123456789"; + let bad_ser = b"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG"; + + let signer = Signer::new( + Some(true), + Some(matter::Codex::CRYSTALS_Dilithium3_Seed), + None, + None, + None, + None, + ) + .unwrap(); + + let siger = signer.sign_indexed(ser, only, index, input_ondex).unwrap(); + assert_eq!(siger.code(), siger_code); + assert_eq!(siger.index(), index); + assert_eq!(siger.ondex(), output_ondex); + assert!(signer.verfer().verify(&siger.raw(), ser).unwrap()); + assert!(!signer.verfer().verify(&siger.raw(), bad_ser).unwrap()); + } + + #[rstest] + #[case(false, 0, None, 0, indexer::Codex::CRYSTALS_Dilithium5)] + #[case(false, 1, None, 1, indexer::Codex::CRYSTALS_Dilithium5)] + #[case(false, 1, Some(3), 3, indexer::Codex::CRYSTALS_Dilithium5_Big)] + #[case(false, 67, Some(3), 3, indexer::Codex::CRYSTALS_Dilithium5_Big)] + #[case(false, 67, Some(67), 67, indexer::Codex::CRYSTALS_Dilithium5_Big)] + #[case(true, 4, None, 0, indexer::Codex::CRYSTALS_Dilithium5_Crt)] + #[case(true, 4, Some(6), 0, indexer::Codex::CRYSTALS_Dilithium5_Crt)] + #[case(true, 65, None, 0, indexer::Codex::CRYSTALS_Dilithium5_Big_Crt)] + #[case(true, 65, Some(67), 0, indexer::Codex::CRYSTALS_Dilithium5_Big_Crt)] + fn sign_crystals_dilithium5_indexed( + #[case] only: bool, + #[case] index: u32, + #[case] input_ondex: Option, + #[case] output_ondex: u32, + #[case] siger_code: &str, + ) { + let ser = b"abcdefghijklmnopqrstuvwxyz0123456789"; + let bad_ser = b"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG"; + + let signer = Signer::new( + Some(true), + Some(matter::Codex::CRYSTALS_Dilithium5_Seed), + None, + None, + None, + None, + ) + .unwrap(); + + let siger = signer.sign_indexed(ser, only, index, input_ondex).unwrap(); + assert_eq!(siger.code(), siger_code); + assert_eq!(siger.index(), index); + assert_eq!(siger.ondex(), output_ondex); + assert!(signer.verfer().verify(&siger.raw(), ser).unwrap()); + assert!(!signer.verfer().verify(&siger.raw(), bad_ser).unwrap()); + } + #[test] fn unhappy_paths() { let raw: [u8; 32] = [0; 32]; diff --git a/src/core/verfer.rs b/src/core/verfer.rs index 78d050f..41194c7 100644 --- a/src/core/verfer.rs +++ b/src/core/verfer.rs @@ -23,6 +23,10 @@ fn validate_code(code: &str) -> Result<()> { matter::Codex::ECDSA_256k1, matter::Codex::ECDSA_256r1N, matter::Codex::ECDSA_256r1, + matter::Codex::CRYSTALS_Dilithium3N, + matter::Codex::CRYSTALS_Dilithium3, + matter::Codex::CRYSTALS_Dilithium5N, + matter::Codex::CRYSTALS_Dilithium5, // matter::Codex::Ed448N, // matter::Codex::Ed448, ]; diff --git a/src/crypto/sign.rs b/src/crypto/sign.rs index 44717c0..09bacfe 100644 --- a/src/crypto/sign.rs +++ b/src/crypto/sign.rs @@ -15,6 +15,14 @@ pub(crate) fn generate(code: &str) -> Result> { | matter::Codex::ECDSA_256r1N | matter::Codex::ECDSA_256r1_Seed | matter::Codex::ECDSA_256r1_Sig => ecdsa_256r1::generate(), + matter::Codex::CRYSTALS_Dilithium3 + | matter::Codex::CRYSTALS_Dilithium3N + | matter::Codex::CRYSTALS_Dilithium3_Seed + | matter::Codex::CRYSTALS_Dilithium3_Sig => crystals_dilithium3::generate(), + matter::Codex::CRYSTALS_Dilithium5 + | matter::Codex::CRYSTALS_Dilithium5N + | matter::Codex::CRYSTALS_Dilithium5_Seed + | matter::Codex::CRYSTALS_Dilithium5_Sig => crystals_dilithium5::generate(), _ => err!(Error::UnexpectedCode(code.to_string())), } } @@ -33,6 +41,14 @@ pub(crate) fn public_key(code: &str, private_key: &[u8]) -> Result> { | matter::Codex::ECDSA_256r1N | matter::Codex::ECDSA_256r1_Seed | matter::Codex::ECDSA_256r1_Sig => ecdsa_256r1::public_key(private_key), + matter::Codex::CRYSTALS_Dilithium3 + | matter::Codex::CRYSTALS_Dilithium3N + | matter::Codex::CRYSTALS_Dilithium3_Seed + | matter::Codex::CRYSTALS_Dilithium3_Sig => crystals_dilithium3::public_key(private_key), + matter::Codex::CRYSTALS_Dilithium5 + | matter::Codex::CRYSTALS_Dilithium5N + | matter::Codex::CRYSTALS_Dilithium5_Seed + | matter::Codex::CRYSTALS_Dilithium5_Sig => crystals_dilithium5::public_key(private_key), _ => err!(Error::UnexpectedCode(code.to_string())), } } @@ -51,6 +67,14 @@ pub(crate) fn sign(code: &str, private_key: &[u8], ser: &[u8]) -> Result | matter::Codex::ECDSA_256r1N | matter::Codex::ECDSA_256r1_Seed | matter::Codex::ECDSA_256r1_Sig => ecdsa_256r1::sign(private_key, ser), + matter::Codex::CRYSTALS_Dilithium3 + | matter::Codex::CRYSTALS_Dilithium3N + | matter::Codex::CRYSTALS_Dilithium3_Seed + | matter::Codex::CRYSTALS_Dilithium3_Sig => crystals_dilithium3::sign(private_key, ser), + matter::Codex::CRYSTALS_Dilithium5 + | matter::Codex::CRYSTALS_Dilithium5N + | matter::Codex::CRYSTALS_Dilithium5_Seed + | matter::Codex::CRYSTALS_Dilithium5_Sig => crystals_dilithium5::sign(private_key, ser), _ => err!(Error::UnexpectedCode(code.to_string())), } } @@ -69,6 +93,18 @@ pub(crate) fn verify(code: &str, public_key: &[u8], sig: &[u8], ser: &[u8]) -> R | matter::Codex::ECDSA_256r1N | matter::Codex::ECDSA_256r1_Seed | matter::Codex::ECDSA_256r1_Sig => ecdsa_256r1::verify(public_key, sig, ser), + matter::Codex::CRYSTALS_Dilithium3 + | matter::Codex::CRYSTALS_Dilithium3N + | matter::Codex::CRYSTALS_Dilithium3_Seed + | matter::Codex::CRYSTALS_Dilithium3_Sig => { + crystals_dilithium3::verify(public_key, sig, ser) + } + matter::Codex::CRYSTALS_Dilithium5 + | matter::Codex::CRYSTALS_Dilithium5N + | matter::Codex::CRYSTALS_Dilithium5_Seed + | matter::Codex::CRYSTALS_Dilithium5_Sig => { + crystals_dilithium5::verify(public_key, sig, ser) + } _ => err!(Error::UnexpectedCode(code.to_string())), } } @@ -192,6 +228,78 @@ mod ecdsa_256r1 { } } +mod crystals_dilithium3 { + use crystals_dilithium::dilithium3::{Keypair, PublicKey}; + use zeroize::Zeroize; + + use crate::crypto::csprng; + use crate::error::Result; + + pub(crate) fn generate() -> Result> { + let mut bytes = [0u8; 32]; + csprng::fill_bytes(&mut bytes); + + let result = bytes.to_vec(); + bytes.zeroize(); + + Ok(result) + } + + pub(crate) fn public_key(seed: &[u8]) -> Result> { + let keypair = Keypair::generate(Some(seed)); + Ok(keypair.public.to_bytes().to_vec()) + } + + pub(crate) fn sign(seed: &[u8], ser: &[u8]) -> Result> { + let keypair = Keypair::generate(Some(seed)); + let mut signature = keypair.sign(ser); + let result = signature.to_vec(); + signature.zeroize(); + Ok(result) + } + + pub(crate) fn verify(public_key: &[u8], sig: &[u8], ser: &[u8]) -> Result { + let public_key = PublicKey::from_bytes(public_key); + Ok(public_key.verify(ser, sig)) + } +} + +mod crystals_dilithium5 { + use crystals_dilithium::dilithium5::{Keypair, PublicKey}; + use zeroize::Zeroize; + + use crate::crypto::csprng; + use crate::error::Result; + + pub(crate) fn generate() -> Result> { + let mut bytes = [0u8; 32]; + csprng::fill_bytes(&mut bytes); + + let result = bytes.to_vec(); + bytes.zeroize(); + + Ok(result) + } + + pub(crate) fn public_key(seed: &[u8]) -> Result> { + let keypair = Keypair::generate(Some(seed)); + Ok(keypair.public.to_bytes().to_vec()) + } + + pub(crate) fn sign(seed: &[u8], ser: &[u8]) -> Result> { + let keypair = Keypair::generate(Some(seed)); + let mut signature = keypair.sign(ser); + let result = signature.to_vec(); + signature.zeroize(); + Ok(result) + } + + pub(crate) fn verify(public_key: &[u8], sig: &[u8], ser: &[u8]) -> Result { + let public_key = PublicKey::from_bytes(public_key); + Ok(public_key.verify(ser, sig)) + } +} + #[cfg(test)] mod test { use crate::core::matter::tables as matter; @@ -200,13 +308,19 @@ mod test { #[rstest] fn end_to_end( - #[values(matter::Codex::Ed25519, matter::Codex::ECDSA_256k1, matter::Codex::ECDSA_256r1)] + #[values( + matter::Codex::Ed25519, + matter::Codex::ECDSA_256k1, + matter::Codex::ECDSA_256r1, + matter::Codex::CRYSTALS_Dilithium3, + matter::Codex::CRYSTALS_Dilithium5 + )] code: &str, ) { let ser = b"abcdefghijklmnopqrstuvwxyz"; - let private_key = sign::generate(code).unwrap(); - let signature = sign::sign(code, &private_key, ser).unwrap(); - let public_key = sign::public_key(code, &private_key).unwrap(); + let seed = sign::generate(code).unwrap(); + let signature = sign::sign(code, &seed, ser).unwrap(); + let public_key = sign::public_key(code, &seed).unwrap(); assert!(sign::verify(code, &public_key, &signature, ser).unwrap()); }