1use k256::ecdsa::signature::hazmat::PrehashVerifier;
27use sha3::Digest;
28
29mod asn1;
30
31#[cfg(feature = "envelope")]
32pub mod envelope;
33
34#[cfg(feature = "envelope")]
35pub mod deeplink;
36
37#[cfg(feature = "envelope")]
38mod ic_signature_verification;
39
40#[cfg(feature = "identity")]
41pub mod identity;
42
43pub use asn1::*;
44pub use ic_canister_sig_creation::CanisterSigPublicKey;
45
46#[cfg(feature = "envelope")]
47pub use ic_signature_verification::*;
48
49#[cfg(feature = "envelope")]
50pub use envelope::*;
51
52#[cfg(feature = "envelope")]
53pub use deeplink::*;
54
55#[cfg(feature = "identity")]
56pub use identity::*;
57
58pub fn verify_basic_sig(
69 algorithm_id: Algorithm,
70 public_key: &[u8],
71 msg: &[u8],
72 signature: &[u8],
73) -> Result<(), String> {
74 match algorithm_id {
75 Algorithm::Ed25519 => {
76 let public_key = public_key
77 .try_into()
78 .map_err(|_| "Ed25519 public key must be 32 bytes long".to_string())?;
79 let key = ed25519_dalek::VerifyingKey::from_bytes(public_key)
80 .map_err(|err| format!("{err:?}"))?;
81 let sig = ed25519_dalek::Signature::from_slice(signature)
82 .map_err(|err| format!("{err:?}"))?;
83 key.verify_strict(msg, &sig)
84 .map_err(|_| "Ed25519 signature verification failed".to_string())
85 }
86 Algorithm::EcdsaP256 => {
87 let key = p256::ecdsa::VerifyingKey::from_sec1_bytes(public_key)
88 .map_err(|err| format!("{err:?}"))?;
89 let sig =
90 p256::ecdsa::Signature::try_from(signature).map_err(|err| format!("{err:?}"))?;
91
92 let msg_hash = sha256(msg);
93 key.verify_prehash(&msg_hash, &sig)
94 .map_err(|_| "ECDSA P256 signature verification failed".to_string())
95 }
96 Algorithm::EcdsaSecp256k1 => {
97 let key = k256::ecdsa::VerifyingKey::from_sec1_bytes(public_key)
98 .map_err(|err| err.to_string())?;
99 let sig =
100 k256::ecdsa::Signature::try_from(signature).map_err(|err| format!("{err:?}"))?;
101
102 let msg_hash = sha256(msg);
103 key.verify_prehash(&msg_hash, &sig)
104 .map_err(|_| "ECDSA Secp256k1 signature verification failed".to_string())
105 }
106 algorithm => Err(format!(
107 "{algorithm:?} is not supported for basic signature verification"
108 )),
109 }
110}
111
112pub fn sha256(data: &[u8]) -> [u8; 32] {
114 let mut hasher = sha2::Sha256::new();
115 hasher.update(data);
116 hasher.finalize().into()
117}
118
119pub fn sha3_256(data: &[u8]) -> [u8; 32] {
121 let mut hasher = sha3::Sha3_256::new();
122 hasher.update(data);
123 hasher.finalize().into()
124}
125
126pub fn keccak256(data: &[u8]) -> [u8; 32] {
128 let mut hasher = sha3::Keccak256::new();
129 hasher.update(data);
130 hasher.finalize().into()
131}
132
133#[cfg(feature = "identity")]
134pub fn rand_bytes<const N: usize>() -> [u8; N] {
136 use rand::Rng;
137
138 let mut rng = rand::rng();
139 let mut bytes = [0u8; N];
140 rng.fill_bytes(&mut bytes);
141 bytes
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use ic_agent::{
148 Identity,
149 identity::{BasicIdentity, Prime256v1Identity, Secp256k1Identity},
150 };
151 use rand::{Rng, rng};
152
153 const MESSAGE: &[u8] = b"some message";
154
155 fn rand_bytes<const N: usize>() -> [u8; N] {
156 let mut rng = rng();
157 let mut bytes = [0u8; N];
158 rng.fill_bytes(&mut bytes);
159 bytes
160 }
161
162 #[test]
163 fn should_work_with_ed25519() {
164 let sk: [u8; 32] = rand_bytes();
165 let id = BasicIdentity::from_raw_key(&sk);
166 let sig = id.sign_arbitrary(MESSAGE).unwrap();
167 let pk_der = id.public_key().unwrap();
168 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
169 assert_eq!(alg, Algorithm::Ed25519);
170 assert!(verify_basic_sig(alg, &pk, MESSAGE, &sig.signature.unwrap()).is_ok());
171 }
172
173 #[test]
174 fn should_work_with_ecdsa_secp256k1() {
175 let pk_der = hex::decode("3056301006072a8648ce3d020106052b8104000a034200047060f720298ffa0f48d9606abdb013bc82f4ff269f9adc3e7226391af3fad8b30fd6a30deb81d5b4f9e142971085d0ae15b8e222d85af1e17438e630d09b7ef4").unwrap();
176 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
177 assert_eq!(alg, Algorithm::EcdsaSecp256k1);
178 assert!(k256::ecdsa::VerifyingKey::from_sec1_bytes(&pk).is_ok());
179
180 let sk: [u8; 32] = rand_bytes();
181 let sk = k256::ecdsa::SigningKey::from_bytes(&sk.into()).unwrap();
182 let id = Secp256k1Identity::from_private_key(sk.into());
183 let sig = id.sign_arbitrary(MESSAGE).unwrap();
184 let pk_der = id.public_key().unwrap();
185 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
186 assert_eq!(alg, Algorithm::EcdsaSecp256k1);
187 assert!(verify_basic_sig(alg, &pk, MESSAGE, &sig.signature.unwrap()).is_ok());
188 }
189
190 #[test]
191 fn should_work_with_ecdsa_p256() {
192 let pk_der = hex::decode("3059301306072a8648ce3d020106082a8648ce3d03010703420004485c32997ce7c6d38ca82c821185c689d424fac7c9695bb97786c4248aab6428949bcd163e2bcf3eeeac4f200b38fbd053f82c4e1776dc9c6dc8db9b7c35e06f").unwrap();
193 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
194 assert_eq!(alg, Algorithm::EcdsaP256);
195 assert!(p256::ecdsa::VerifyingKey::from_sec1_bytes(&pk).is_ok());
196
197 let sk: [u8; 32] = rand_bytes();
198 let sk = p256::ecdsa::SigningKey::from_bytes(&sk.into()).unwrap();
199 let id = Prime256v1Identity::from_private_key(sk.into());
200 let sig = id.sign_arbitrary(MESSAGE).unwrap();
201 let pk_der = id.public_key().unwrap();
202 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
203 assert_eq!(alg, Algorithm::EcdsaP256);
204 assert!(verify_basic_sig(alg, &pk, MESSAGE, &sig.signature.unwrap()).is_ok());
205 }
206
207 #[test]
208 fn should_work_with_iccsa_pubkey() {
209 let pk_der =
210 hex::decode("301b300c060a2b0601040183b8430102030b007075626c6963206b6579").unwrap();
211 let (alg, _pk) = user_public_key_from_der(&pk_der).unwrap();
212 assert_eq!(alg, Algorithm::IcCanisterSignature);
213 }
214
215 #[test]
216 fn hash_helpers_match_known_vectors() {
217 assert_eq!(
218 hex::encode(sha256(b"abc")),
219 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
220 );
221 assert_eq!(
222 hex::encode(sha3_256(b"abc")),
223 "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"
224 );
225 assert_eq!(
226 hex::encode(keccak256(b"abc")),
227 "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45"
228 );
229 }
230
231 #[test]
232 fn verify_basic_sig_rejects_invalid_inputs() {
233 assert_eq!(
234 verify_basic_sig(Algorithm::IcCanisterSignature, &[], MESSAGE, &[]).unwrap_err(),
235 "IcCanisterSignature is not supported for basic signature verification"
236 );
237
238 assert_eq!(
239 verify_basic_sig(Algorithm::Ed25519, &[0; 31], MESSAGE, &[]).unwrap_err(),
240 "Ed25519 public key must be 32 bytes long"
241 );
242
243 let id = BasicIdentity::from_raw_key(&[8u8; 32]);
244 let sig = id.sign_arbitrary(MESSAGE).unwrap();
245 let pk_der = id.public_key().unwrap();
246 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
247 assert!(verify_basic_sig(alg.clone(), &pk, MESSAGE, &[]).is_err());
248 assert_eq!(
249 verify_basic_sig(alg, &pk, b"tampered", &sig.signature.unwrap()).unwrap_err(),
250 "Ed25519 signature verification failed"
251 );
252
253 let sk: [u8; 32] = rand_bytes();
254 let sk = p256::ecdsa::SigningKey::from_bytes(&sk.into()).unwrap();
255 let id = Prime256v1Identity::from_private_key(sk.into());
256 let pk_der = id.public_key().unwrap();
257 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
258 assert!(verify_basic_sig(alg, &pk, MESSAGE, &[]).is_err());
259
260 let sk: [u8; 32] = rand_bytes();
261 let sk = k256::ecdsa::SigningKey::from_bytes(&sk.into()).unwrap();
262 let id = Secp256k1Identity::from_private_key(sk.into());
263 let pk_der = id.public_key().unwrap();
264 let (alg, pk) = user_public_key_from_der(&pk_der).unwrap();
265 assert!(verify_basic_sig(alg, &pk, MESSAGE, &[]).is_err());
266
267 assert!(verify_basic_sig(Algorithm::EcdsaP256, &[0], MESSAGE, &[]).is_err());
268 assert!(verify_basic_sig(Algorithm::EcdsaSecp256k1, &[0], MESSAGE, &[]).is_err());
269 }
270}