sqisign_verify/lib.rs
1//!
2//! SQIsign signature verification in pure Rust.
3//!
4//! This crate is `no_std`-compatible, heap-free, and independent of the
5//! quaternion algebra stack. It contains all the arithmetic layers needed
6//! for verification: field arithmetic (params, fp), elliptic curves (ec),
7//! theta model (theta), precomputed constants (precomp), and the
8//! verification protocol itself.
9//!
10//! # Verify a signature
11//!
12//! All verification goes through [`pk.verify(msg, &sig)`](Verifier::verify)
13//! via the RustCrypto [`Verifier`] trait. It accepts any signature type:
14//! [`Signature`], [`ExpandedSignature`], [`CompressedSignature`], or
15//! [`AnySignature`](formats::AnySignature) (auto-detected from raw bytes).
16//!
17//! ```
18//! use hex_literal::hex;
19//! use sqisign_verify::{PublicKey, Signature, Verifier};
20//!
21//! # fn main() -> Result<(), sqisign_verify::Error> {
22//! let pk_bytes = hex!(
23//! "07CCD21425136F6E865E497D2D4D208F0054AD81372066E817480787AAF7B202"
24//! "9550C89E892D618CE3230F23510BFBE68FCCDDAEA51DB1436B462ADFAF008A01"
25//! "0B"
26//! );
27//! let sig_bytes = hex!(
28//! "84228651F271B0F39F2F19F2E8718F31ED3365AC9E5CB303AFE663D0CFC11F04"
29//! "55D891B0CA6C7E653F9BA2667730BB77BEFE1B1A31828404284AF8FD7BAACC01"
30//! "0001D974B5CA671FF65708D8B462A5A84A1443EE9B5FED7218767C9D85CEED04"
31//! "DB0A69A2F6EC3BE835B3B2624B9A0DF68837AD00BCACC27D1EC806A448402674"
32//! "71D86EFF3447018ADB0A6551EE8322AB30010202"
33//! );
34//! let msg = hex!(
35//! "D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556A"
36//! "C8"
37//! );
38//!
39//! let pk: PublicKey = PublicKey::from_bytes(&pk_bytes)?;
40//! let sig: Signature = Signature::from_bytes(&sig_bytes)?;
41//! pk.verify(&msg, &sig)?;
42//! # Ok(())
43//! # }
44//! ```
45//!
46//! For raw bytes where the format is unknown, parse into
47//! [`AnySignature`](formats::AnySignature) first:
48//!
49//! ```
50//! use hex_literal::hex;
51//! use sqisign_verify::{formats::AnySignature, PublicKey, Verifier};
52//!
53//! # fn main() -> Result<(), sqisign_verify::Error> {
54//! # let pk_bytes = hex!(
55//! # "07CCD21425136F6E865E497D2D4D208F0054AD81372066E817480787AAF7B202"
56//! # "9550C89E892D618CE3230F23510BFBE68FCCDDAEA51DB1436B462ADFAF008A01"
57//! # "0B"
58//! # );
59//! # let sig_bytes = hex!(
60//! # "84228651F271B0F39F2F19F2E8718F31ED3365AC9E5CB303AFE663D0CFC11F04"
61//! # "55D891B0CA6C7E653F9BA2667730BB77BEFE1B1A31828404284AF8FD7BAACC01"
62//! # "0001D974B5CA671FF65708D8B462A5A84A1443EE9B5FED7218767C9D85CEED04"
63//! # "DB0A69A2F6EC3BE835B3B2624B9A0DF68837AD00BCACC27D1EC806A448402674"
64//! # "71D86EFF3447018ADB0A6551EE8322AB30010202"
65//! # );
66//! # let msg = hex!(
67//! # "D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556A"
68//! # "C8"
69//! # );
70//! let pk: PublicKey = PublicKey::from_bytes(&pk_bytes)?;
71//! let sig = AnySignature::from_bytes(&sig_bytes)?;
72//! pk.verify(&msg, &sig)?;
73//! # Ok(())
74//! # }
75//! ```
76
77#![no_std]
78#![forbid(unsafe_code)]
79
80pub mod ec;
81pub mod fp;
82pub mod params;
83pub mod precomp;
84pub mod theta;
85
86pub mod formats;
87pub mod hash;
88pub mod types;
89pub mod verify;
90
91pub use formats::{CompressedSignature, ExpandedSignature};
92pub use hash::hash_to_challenge;
93pub use types::{PublicKey, Scalar, Signature};
94
95pub use fp::{Fp, Fp2, FpBackend};
96pub use params::{Level1, Level3, Level5, SecurityLevel};
97pub use precomp::LevelPrecomp;
98pub use signature::{self, SignatureEncoding, Verifier};
99
100/// Error type for verification failures.
101#[derive(Clone, Debug, PartialEq, Eq)]
102pub enum Error {
103 /// The signature is cryptographically invalid.
104 InvalidSignature,
105 /// The input bytes could not be deserialized.
106 MalformedInput,
107 /// The input length does not match the expected encoding size.
108 InvalidLength,
109 /// An internal computation failed (e.g. hash-to-challenge buffer conversion).
110 InternalError,
111}
112
113impl core::fmt::Display for Error {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 match self {
116 Error::InvalidSignature => f.write_str("invalid signature"),
117 Error::MalformedInput => f.write_str("malformed input"),
118 Error::InvalidLength => f.write_str("invalid length"),
119 Error::InternalError => f.write_str("internal error"),
120 }
121 }
122}
123
124impl From<signature::Error> for Error {
125 #[inline]
126 fn from(_: signature::Error) -> Self {
127 Error::InvalidSignature
128 }
129}
130
131#[cfg(feature = "std")]
132extern crate std;
133
134#[cfg(feature = "std")]
135impl std::error::Error for Error {}