1use anyhow::{anyhow, bail, ensure, Context, Result};
12use chacha20poly1305::{
13 aead::{Aead, KeyInit, Payload},
14 ChaCha20Poly1305, Key, Nonce,
15};
16use secp256k1::{
17 ellswift::{ElligatorSwift, ElligatorSwiftParty, ElligatorSwiftSharedSecret},
18 schnorr::Signature,
19 Keypair, Message, PublicKey, Secp256k1, SecretKey, XOnlyPublicKey,
20};
21use sha2::{Digest, Sha256};
22
23pub const PROTOCOL_NAME: &str = "Noise_NX_Secp256k1+EllSwift_ChaChaPoly_SHA256";
25pub const ELLSWIFT_LEN: usize = 64;
27pub const MAC_LEN: usize = 16;
29pub const SIGNATURE_MESSAGE_LEN: usize = 2 + 4 + 4 + 64;
31pub const INITIATOR_MESSAGE_LEN: usize = ELLSWIFT_LEN;
33pub const RESPONDER_MESSAGE_LEN: usize =
35 ELLSWIFT_LEN + ELLSWIFT_LEN + MAC_LEN + SIGNATURE_MESSAGE_LEN + MAC_LEN;
36pub const CERTIFICATE_VERSION: u16 = 0;
38pub const CERTIFICATE_LEEWAY_SECS: u32 = 10;
40pub const MAX_CIPHERTEXT_CHUNK: usize = 65535;
42pub const MAX_PLAINTEXT_CHUNK: usize = MAX_CIPHERTEXT_CHUNK - MAC_LEN;
44pub const AUTHORITY_KEY_VERSION: u16 = 1;
46
47pub fn sha256(parts: &[&[u8]]) -> [u8; 32] {
48 let mut h = Sha256::new();
49 for p in parts {
50 h.update(p);
51 }
52 h.finalize().into()
53}
54
55pub fn hmac_sha256(key: &[u8; 32], data: &[&[u8]]) -> [u8; 32] {
57 let mut ipad = [0x36u8; 64];
58 let mut opad = [0x5cu8; 64];
59 for i in 0..32 {
60 ipad[i] ^= key[i];
61 opad[i] ^= key[i];
62 }
63 let mut inner = Sha256::new();
64 inner.update(ipad);
65 for d in data {
66 inner.update(d);
67 }
68 let inner: [u8; 32] = inner.finalize().into();
69 sha256(&[&opad, &inner])
70}
71
72pub fn hkdf2(chaining_key: &[u8; 32], ikm: &[u8]) -> ([u8; 32], [u8; 32]) {
74 let temp = hmac_sha256(chaining_key, &[ikm]);
75 let out1 = hmac_sha256(&temp, &[&[0x01]]);
76 let out2 = hmac_sha256(&temp, &[&out1, &[0x02]]);
77 (out1, out2)
78}
79
80#[derive(Clone)]
82pub struct CipherState {
83 key: Option<[u8; 32]>,
84 n: u64,
85}
86
87impl CipherState {
88 pub fn empty() -> Self {
89 Self { key: None, n: 0 }
90 }
91
92 pub fn with_key(key: [u8; 32]) -> Self {
93 Self {
94 key: Some(key),
95 n: 0,
96 }
97 }
98
99 pub fn nonce_value(&self) -> u64 {
101 self.n
102 }
103
104 fn nonce(&self) -> [u8; 12] {
106 let mut n = [0u8; 12];
107 n[4..].copy_from_slice(&self.n.to_le_bytes());
108 n
109 }
110
111 pub fn encrypt(&mut self, ad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>> {
112 let Some(key) = self.key else {
113 return Ok(plaintext.to_vec());
114 };
115 ensure!(self.n != u64::MAX, "Noise nonce exhausted");
116 let out = ChaCha20Poly1305::new(&Key::from(key))
117 .encrypt(
118 &Nonce::from(self.nonce()),
119 Payload {
120 msg: plaintext,
121 aad: ad,
122 },
123 )
124 .map_err(|_| anyhow!("Noise encryption failed"))?;
125 self.n += 1;
126 Ok(out)
127 }
128
129 pub fn decrypt(&mut self, ad: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
131 let Some(key) = self.key else {
132 return Ok(ciphertext.to_vec());
133 };
134 ensure!(self.n != u64::MAX, "Noise nonce exhausted");
135 ensure!(
136 ciphertext.len() >= MAC_LEN,
137 "Noise message shorter than its MAC"
138 );
139 let out = ChaCha20Poly1305::new(&Key::from(key))
140 .decrypt(
141 &Nonce::from(self.nonce()),
142 Payload {
143 msg: ciphertext,
144 aad: ad,
145 },
146 )
147 .map_err(|_| anyhow!("Noise MAC check failed"))?;
148 self.n += 1;
149 Ok(out)
150 }
151}
152
153struct Symmetric {
155 ck: [u8; 32],
156 h: [u8; 32],
157 cipher: CipherState,
158}
159
160impl Symmetric {
161 fn new() -> Self {
162 let h = sha256(&[PROTOCOL_NAME.as_bytes()]);
164 Self {
165 ck: h,
166 h: sha256(&[&h]),
167 cipher: CipherState::empty(),
168 }
169 }
170
171 fn mix_hash(&mut self, data: &[u8]) {
172 self.h = sha256(&[&self.h, data]);
173 }
174
175 fn mix_key(&mut self, ikm: &[u8]) {
176 let (ck, k) = hkdf2(&self.ck, ikm);
177 self.ck = ck;
178 self.cipher = CipherState::with_key(k);
179 }
180
181 fn encrypt_and_hash(&mut self, plaintext: &[u8]) -> Result<Vec<u8>> {
182 let h = self.h;
183 let ct = self.cipher.encrypt(&h, plaintext)?;
184 self.mix_hash(&ct);
185 Ok(ct)
186 }
187
188 fn decrypt_and_hash(&mut self, ciphertext: &[u8]) -> Result<Vec<u8>> {
189 let h = self.h;
190 let pt = self.cipher.decrypt(&h, ciphertext)?;
191 self.mix_hash(ciphertext);
192 Ok(pt)
193 }
194
195 fn split(&self) -> (CipherState, CipherState) {
197 let (k1, k2) = hkdf2(&self.ck, &[]);
198 (CipherState::with_key(k1), CipherState::with_key(k2))
199 }
200}
201
202pub struct EllKey {
204 secret: SecretKey,
205 ellswift: [u8; ELLSWIFT_LEN],
206}
207
208impl EllKey {
209 pub fn generate() -> Self {
210 loop {
211 if let Ok(secret) = SecretKey::from_slice(&rand::random::<[u8; 32]>()) {
212 return Self::from_secret(secret);
213 }
214 }
215 }
216
217 pub fn from_secret(secret: SecretKey) -> Self {
218 let ellswift =
220 ElligatorSwift::from_seckey(&Secp256k1::new(), secret, Some(rand::random())).to_array();
221 Self { secret, ellswift }
222 }
223
224 pub fn ellswift(&self) -> [u8; ELLSWIFT_LEN] {
225 self.ellswift
226 }
227
228 pub fn xonly(&self) -> [u8; 32] {
230 self.secret
231 .x_only_public_key(&Secp256k1::signing_only())
232 .0
233 .serialize()
234 }
235
236 fn ecdh(&self, theirs: &[u8; ELLSWIFT_LEN], initiator: bool) -> [u8; 32] {
239 let ours = ElligatorSwift::from_array(self.ellswift);
240 let other = ElligatorSwift::from_array(*theirs);
241 let (a, b, party) = if initiator {
242 (ours, other, ElligatorSwiftParty::A)
243 } else {
244 (other, ours, ElligatorSwiftParty::B)
245 };
246 let mut x32 = [0u8; 32];
247 ElligatorSwift::shared_secret_with_hasher(a, b, self.secret, party, |x, _, _| {
248 x32 = x;
249 ElligatorSwiftSharedSecret::from_secret_bytes([0u8; 32])
250 });
251 let (ell_a, ell_b) = if initiator {
252 (self.ellswift, *theirs)
253 } else {
254 (*theirs, self.ellswift)
255 };
256 let tag = sha256(&[b"bip324_ellswift_xonly_ecdh"]);
257 sha256(&[&tag, &tag, &ell_a, &ell_b, &x32])
258 }
259}
260
261pub fn ellswift_xonly(ell: &[u8; ELLSWIFT_LEN]) -> [u8; 32] {
263 PublicKey::from_ellswift(ElligatorSwift::from_array(*ell))
264 .x_only_public_key()
265 .0
266 .serialize()
267}
268
269pub struct Authority {
271 keypair: Keypair,
272}
273
274impl Authority {
275 pub fn generate() -> Self {
276 let secp = Secp256k1::new();
277 loop {
278 if let Ok(secret) = SecretKey::from_slice(&rand::random::<[u8; 32]>()) {
279 return Self {
280 keypair: Keypair::from_secret_key(&secp, &secret),
281 };
282 }
283 }
284 }
285
286 pub fn from_secret_bytes(bytes: &[u8]) -> Result<Self> {
287 let secret = SecretKey::from_slice(bytes).context("not a valid secp256k1 secret key")?;
288 Ok(Self {
289 keypair: Keypair::from_secret_key(&Secp256k1::new(), &secret),
290 })
291 }
292
293 pub fn public_xonly(&self) -> [u8; 32] {
294 self.keypair.x_only_public_key().0.serialize()
295 }
296
297 pub fn certify(
299 &self,
300 server_xonly: &[u8; 32],
301 valid_from: u32,
302 not_valid_after: u32,
303 ) -> [u8; SIGNATURE_MESSAGE_LEN] {
304 let mut out = [0u8; SIGNATURE_MESSAGE_LEN];
305 out[0..2].copy_from_slice(&CERTIFICATE_VERSION.to_le_bytes());
306 out[2..6].copy_from_slice(&valid_from.to_le_bytes());
307 out[6..10].copy_from_slice(¬_valid_after.to_le_bytes());
308 let m = certificate_digest(&out[0..10], server_xonly);
309 let sig = Secp256k1::signing_only().sign_schnorr_with_aux_rand(
310 &Message::from_digest(m),
311 &self.keypair,
312 &rand::random(),
313 );
314 out[10..].copy_from_slice(sig.as_ref());
315 out
316 }
317}
318
319fn certificate_digest(signed_head: &[u8], server_xonly: &[u8; 32]) -> [u8; 32] {
321 sha256(&[signed_head, server_xonly])
322}
323
324#[derive(Debug, Clone)]
326pub struct Certificate {
327 pub version: u16,
328 pub valid_from: u32,
329 pub not_valid_after: u32,
330 pub server_xonly: [u8; 32],
331}
332
333pub fn verify_certificate(
335 message: &[u8; SIGNATURE_MESSAGE_LEN],
336 server_xonly: &[u8; 32],
337 authority: &[u8; 32],
338 now: u32,
339) -> Result<Certificate> {
340 let version = u16::from_le_bytes([message[0], message[1]]);
341 let valid_from = u32::from_le_bytes(message[2..6].try_into().expect("4 bytes"));
342 let not_valid_after = u32::from_le_bytes(message[6..10].try_into().expect("4 bytes"));
343 ensure!(
344 version == CERTIFICATE_VERSION,
345 "certificate version {version} is not supported"
346 );
347 ensure!(
348 valid_from.saturating_sub(CERTIFICATE_LEEWAY_SECS) <= now
349 && now <= not_valid_after.saturating_add(CERTIFICATE_LEEWAY_SECS),
350 "certificate is valid from {valid_from} to {not_valid_after}, and it is {now}"
351 );
352 let authority = XOnlyPublicKey::from_slice(authority).context("authority key is invalid")?;
353 let sig =
354 Signature::from_slice(&message[10..]).context("certificate signature is malformed")?;
355 let m = certificate_digest(&message[0..10], server_xonly);
356 Secp256k1::verification_only()
357 .verify_schnorr(&sig, &Message::from_digest(m), &authority)
358 .map_err(|_| anyhow!("certificate is not signed by the configured authority"))?;
359 Ok(Certificate {
360 version,
361 valid_from,
362 not_valid_after,
363 server_xonly: *server_xonly,
364 })
365}
366
367pub struct Session {
369 pub send: CipherState,
370 pub recv: CipherState,
371}
372
373pub fn respond(
375 initiator_message: &[u8; INITIATOR_MESSAGE_LEN],
376 static_key: &EllKey,
377 authority: &Authority,
378 validity_secs: u32,
379 now: u32,
380) -> Result<([u8; RESPONDER_MESSAGE_LEN], Session)> {
381 let mut sym = Symmetric::new();
382 let re = *initiator_message;
383 sym.mix_hash(&re);
384 sym.decrypt_and_hash(&[])?;
385
386 let e = EllKey::generate();
387 let mut out = Vec::with_capacity(RESPONDER_MESSAGE_LEN);
388 out.extend_from_slice(&e.ellswift());
389 sym.mix_hash(&e.ellswift());
390 sym.mix_key(&e.ecdh(&re, false));
391 out.extend_from_slice(&sym.encrypt_and_hash(&static_key.ellswift())?);
392 sym.mix_key(&static_key.ecdh(&re, false));
393 let certificate =
394 authority.certify(&static_key.xonly(), now, now.saturating_add(validity_secs));
395 out.extend_from_slice(&sym.encrypt_and_hash(&certificate)?);
396 let (c1, c2) = sym.split();
397 let message: [u8; RESPONDER_MESSAGE_LEN] = out
398 .try_into()
399 .map_err(|_| anyhow!("responder message has the wrong length"))?;
400 Ok((message, Session { send: c2, recv: c1 }))
401}
402
403pub struct Initiator {
405 sym: Symmetric,
406 e: EllKey,
407}
408
409impl Initiator {
410 pub fn start() -> Result<(Self, [u8; INITIATOR_MESSAGE_LEN])> {
412 let mut sym = Symmetric::new();
413 let e = EllKey::generate();
414 sym.mix_hash(&e.ellswift());
415 sym.encrypt_and_hash(&[])?;
416 let msg = e.ellswift();
417 Ok((Self { sym, e }, msg))
418 }
419
420 pub fn finish(
422 mut self,
423 message: &[u8; RESPONDER_MESSAGE_LEN],
424 authority: &[u8; 32],
425 now: u32,
426 ) -> Result<(Session, Certificate)> {
427 let re: [u8; ELLSWIFT_LEN] = message[..ELLSWIFT_LEN].try_into().expect("64 bytes");
428 self.sym.mix_hash(&re);
429 self.sym.mix_key(&self.e.ecdh(&re, true));
430 let rs = self
431 .sym
432 .decrypt_and_hash(&message[ELLSWIFT_LEN..ELLSWIFT_LEN * 2 + MAC_LEN])
433 .context("the responder's static key did not authenticate")?;
434 let rs: [u8; ELLSWIFT_LEN] = rs
435 .try_into()
436 .map_err(|_| anyhow!("static key has the wrong length"))?;
437 self.sym.mix_key(&self.e.ecdh(&rs, true));
438 let cert = self
439 .sym
440 .decrypt_and_hash(&message[ELLSWIFT_LEN * 2 + MAC_LEN..])
441 .context("the responder's certificate did not authenticate")?;
442 let cert: [u8; SIGNATURE_MESSAGE_LEN] = cert
443 .try_into()
444 .map_err(|_| anyhow!("certificate has the wrong length"))?;
445 let certificate = verify_certificate(&cert, &ellswift_xonly(&rs), authority, now)?;
446 let (c1, c2) = self.sym.split();
447 Ok((Session { send: c1, recv: c2 }, certificate))
448 }
449}
450
451const BASE58: &[u8; 58] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
452
453pub fn base58check_encode(payload: &[u8]) -> String {
455 let check = sha256(&[&sha256(&[payload])]);
456 let mut data = payload.to_vec();
457 data.extend_from_slice(&check[..4]);
458 let zeros = data.iter().take_while(|b| **b == 0).count();
459 let mut digits: Vec<u8> = Vec::new();
460 for &byte in &data {
461 let mut carry = u32::from(byte);
462 for d in digits.iter_mut() {
463 carry += u32::from(*d) << 8;
464 *d = (carry % 58) as u8;
465 carry /= 58;
466 }
467 while carry > 0 {
468 digits.push((carry % 58) as u8);
469 carry /= 58;
470 }
471 }
472 let mut out = String::with_capacity(zeros + digits.len());
473 out.extend(std::iter::repeat_n('1', zeros));
474 out.extend(digits.iter().rev().map(|d| BASE58[*d as usize] as char));
475 out
476}
477
478pub fn base58check_decode(text: &str) -> Result<Vec<u8>> {
479 ensure!(text.len() <= 128, "base58 string is too long");
480 let zeros = text.bytes().take_while(|b| *b == b'1').count();
481 let mut bytes: Vec<u8> = Vec::new();
482 for c in text.bytes() {
483 let Some(value) = BASE58.iter().position(|b| *b == c) else {
484 bail!("{:?} is not a base58 character", c as char);
485 };
486 let mut carry = value as u32;
487 for b in bytes.iter_mut() {
488 carry += u32::from(*b) * 58;
489 *b = (carry & 0xff) as u8;
490 carry >>= 8;
491 }
492 while carry > 0 {
493 bytes.push((carry & 0xff) as u8);
494 carry >>= 8;
495 }
496 }
497 let mut data = vec![0u8; zeros];
498 data.extend(bytes.iter().rev());
499 ensure!(data.len() >= 4, "base58check string is too short");
500 let (payload, check) = data.split_at(data.len() - 4);
501 ensure!(
502 sha256(&[&sha256(&[payload])])[..4] == *check,
503 "base58check checksum does not match"
504 );
505 Ok(payload.to_vec())
506}
507
508pub fn encode_authority_key(xonly: &[u8; 32]) -> String {
510 let mut payload = AUTHORITY_KEY_VERSION.to_le_bytes().to_vec();
511 payload.extend_from_slice(xonly);
512 base58check_encode(&payload)
513}
514
515pub fn decode_authority_key(text: &str) -> Result<[u8; 32]> {
516 let payload = base58check_decode(text.trim())?;
517 ensure!(
518 payload.len() == 34,
519 "an authority public key is 34 bytes once decoded"
520 );
521 let version = u16::from_le_bytes([payload[0], payload[1]]);
522 ensure!(
523 version == AUTHORITY_KEY_VERSION,
524 "authority key version {version} is not supported"
525 );
526 let key: [u8; 32] = payload[2..].try_into().expect("32 bytes");
527 XOnlyPublicKey::from_slice(&key).context("authority key is not a secp256k1 point")?;
528 Ok(key)
529}
530
531pub fn decode_secret_key(text: &str) -> Result<Authority> {
533 let payload = base58check_decode(text.trim())?;
534 ensure!(payload.len() == 32, "a secret key is 32 bytes once decoded");
535 Authority::from_secret_bytes(&payload)
536}
537
538pub fn encode_secret_key(bytes: &[u8; 32]) -> String {
539 base58check_encode(bytes)
540}
541
542impl Authority {
543 pub fn secret_bytes(&self) -> [u8; 32] {
544 self.keypair.secret_bytes()
545 }
546}