1#![allow(clippy::needless_range_loop)]
10
11use crate::Hasher;
66use crate::hash::sha512::Sha512;
67
68#[derive(Clone, Copy, Debug)]
74struct Fe25519([u64; 4]);
75
76const P: [u64; 4] = [
78 0xFFFF_FFFF_FFFF_FFED,
79 0xFFFF_FFFF_FFFF_FFFF,
80 0xFFFF_FFFF_FFFF_FFFF,
81 0x7FFF_FFFF_FFFF_FFFF,
82];
83
84impl Fe25519 {
85 const ZERO: Fe25519 = Fe25519([0, 0, 0, 0]);
86 const ONE: Fe25519 = Fe25519([1, 0, 0, 0]);
87
88 fn reduce(mut limbs: [u64; 4]) -> Self {
90 let (r0, borrow) = limbs[0].overflowing_sub(P[0]);
92 let (r1, borrow) = sbb(limbs[1], P[1], borrow);
93 let (r2, borrow) = sbb(limbs[2], P[2], borrow);
94 let (r3, borrow) = sbb(limbs[3], P[3], borrow);
95
96 let mask = if borrow { u64::MAX } else { 0 };
98 limbs[0] = (limbs[0] & mask) | (r0 & !mask);
99 limbs[1] = (limbs[1] & mask) | (r1 & !mask);
100 limbs[2] = (limbs[2] & mask) | (r2 & !mask);
101 limbs[3] = (limbs[3] & mask) | (r3 & !mask);
102
103 Fe25519(limbs)
104 }
105
106 fn add(self, rhs: Self) -> Self {
107 let (r0, carry) = self.0[0].overflowing_add(rhs.0[0]);
108 let (r1, carry) = adc(self.0[1], rhs.0[1], carry);
109 let (r2, carry) = adc(self.0[2], rhs.0[2], carry);
110 let (r3, _carry) = adc(self.0[3], rhs.0[3], carry);
111 Fe25519::reduce([r0, r1, r2, r3])
112 }
113
114 fn sub(self, rhs: Self) -> Self {
115 let (r0, borrow) = self.0[0].overflowing_sub(rhs.0[0]);
116 let (r1, borrow) = sbb(self.0[1], rhs.0[1], borrow);
117 let (r2, borrow) = sbb(self.0[2], rhs.0[2], borrow);
118 let (r3, borrow) = sbb(self.0[3], rhs.0[3], borrow);
119
120 let mask = if borrow { u64::MAX } else { 0 };
122 let (r0, carry) = r0.overflowing_add(P[0] & mask);
123 let (r1, carry) = adc(r1, P[1] & mask, carry);
124 let (r2, carry) = adc(r2, P[2] & mask, carry);
125 let (r3, _) = adc(r3, P[3] & mask, carry);
126
127 Fe25519([r0, r1, r2, r3])
128 }
129
130 fn neg(self) -> Self {
131 Fe25519::ZERO.sub(self)
132 }
133
134 fn mul(self, rhs: Self) -> Self {
136 let wide = mul256(self.0, rhs.0);
137 fe_reduce_wide(wide)
138 }
139
140 fn square(self) -> Self {
141 self.mul(self)
142 }
143
144 fn pow(self, exp: [u64; 4]) -> Self {
146 let mut result = Fe25519::ONE;
147 let mut base = self;
148 for i in 0..4 {
149 let mut e = exp[i];
150 for _ in 0..64 {
151 if e & 1 == 1 {
152 result = result.mul(base);
153 }
154 base = base.square();
155 e >>= 1;
156 }
157 }
158 result
159 }
160
161 fn inv(self) -> Self {
163 let pm2: [u64; 4] = [
165 0xFFFF_FFFF_FFFF_FFEB,
166 0xFFFF_FFFF_FFFF_FFFF,
167 0xFFFF_FFFF_FFFF_FFFF,
168 0x7FFF_FFFF_FFFF_FFFF,
169 ];
170 self.pow(pm2)
171 }
172
173 fn equals(self, other: Self) -> bool {
175 let a = Fe25519::reduce(self.0);
176 let b = Fe25519::reduce(other.0);
177 let mut acc = 0u64;
178 for i in 0..4 {
179 acc |= a.0[i] ^ b.0[i];
180 }
181 acc == 0
182 }
183
184 fn is_zero(self) -> bool {
185 self.equals(Fe25519::ZERO)
186 }
187
188 fn to_bytes(self) -> [u8; 32] {
190 let r = Fe25519::reduce(self.0);
191 let mut out = [0u8; 32];
192 out[0..8].copy_from_slice(&r.0[0].to_le_bytes());
193 out[8..16].copy_from_slice(&r.0[1].to_le_bytes());
194 out[16..24].copy_from_slice(&r.0[2].to_le_bytes());
195 out[24..32].copy_from_slice(&r.0[3].to_le_bytes());
196 out
197 }
198
199 fn from_bytes(bytes: &[u8; 32]) -> Self {
201 let mut limbs = [0u64; 4];
202 limbs[0] = u64::from_le_bytes(bytes[0..8].try_into().unwrap());
203 limbs[1] = u64::from_le_bytes(bytes[8..16].try_into().unwrap());
204 limbs[2] = u64::from_le_bytes(bytes[16..24].try_into().unwrap());
205 limbs[3] = u64::from_le_bytes(bytes[24..32].try_into().unwrap());
206 limbs[3] &= 0x7FFF_FFFF_FFFF_FFFF;
207 Fe25519::reduce(limbs)
208 }
209
210 fn from_u64(v: u64) -> Self {
211 Fe25519([v, 0, 0, 0])
212 }
213
214 fn is_odd(self) -> u8 {
216 let r = Fe25519::reduce(self.0);
217 (r.0[0] & 1) as u8
218 }
219
220 fn ct_select(a: Self, b: Self, choice: u8) -> Self {
222 let mask = (choice as u64).wrapping_neg();
223 Fe25519([
224 a.0[0] ^ (mask & (a.0[0] ^ b.0[0])),
225 a.0[1] ^ (mask & (a.0[1] ^ b.0[1])),
226 a.0[2] ^ (mask & (a.0[2] ^ b.0[2])),
227 a.0[3] ^ (mask & (a.0[3] ^ b.0[3])),
228 ])
229 }
230}
231
232#[inline(always)]
235fn adc(a: u64, b: u64, carry_in: bool) -> (u64, bool) {
236 let (s1, c1) = a.overflowing_add(b);
237 let (s2, c2) = s1.overflowing_add(carry_in as u64);
238 (s2, c1 | c2)
239}
240
241#[inline(always)]
242fn sbb(a: u64, b: u64, borrow_in: bool) -> (u64, bool) {
243 let (s1, b1) = a.overflowing_sub(b);
244 let (s2, b2) = s1.overflowing_sub(borrow_in as u64);
245 (s2, b1 | b2)
246}
247
248#[inline(always)]
249fn mul64(a: u64, b: u64) -> u128 {
250 (a as u128) * (b as u128)
251}
252
253fn mul256(a: [u64; 4], b: [u64; 4]) -> [u64; 8] {
255 let mut r = [0u64; 8];
256 for i in 0..4 {
257 let mut carry = 0u64;
258 for j in 0..4 {
259 let uv = mul64(a[i], b[j]) + r[i + j] as u128 + carry as u128;
260 r[i + j] = uv as u64;
261 carry = (uv >> 64) as u64;
262 }
263 r[i + 4] = carry;
264 }
265 r
266}
267
268fn fe_reduce_wide(w: [u64; 8]) -> Fe25519 {
272 let low3_top_bit = (w[3] >> 63) & 1;
274 let low = [w[0], w[1], w[2], w[3] & 0x7FFF_FFFF_FFFF_FFFF];
275
276 let high = [
278 (w[4] << 1) | low3_top_bit,
279 (w[5] << 1) | (w[4] >> 63),
280 (w[6] << 1) | (w[5] >> 63),
281 (w[7] << 1) | (w[6] >> 63),
282 w[7] >> 63,
283 ];
284
285 let mut acc = [0u64; 5];
287 let mut carry = 0u128;
288 for i in 0..5 {
289 carry += low.get(i).copied().unwrap_or(0) as u128 + 19u128 * high[i] as u128;
290 acc[i] = carry as u64;
291 carry >>= 64;
292 }
293
294 let top_bit = (acc[3] >> 63) & 1;
296 acc[3] &= 0x7FFF_FFFF_FFFF_FFFF;
297 let extra = (acc[4] << 1) | top_bit;
298
299 let add = extra as u128 * 19;
301 let (r0, c) = acc[0].overflowing_add(add as u64);
302 let (r1, c) = adc(acc[1], (add >> 64) as u64, c);
303 let (r2, c) = adc(acc[2], 0, c);
304 let (r3, _) = adc(acc[3], 0, c);
305
306 Fe25519::reduce([r0, r1, r2, r3])
307}
308
309const L: [u64; 4] = [
315 0x5812631A5CF5D3ED,
316 0x14DEF9DEA2F79CD6,
317 0x0000000000000000,
318 0x1000000000000000,
319];
320
321fn sc_reduce(input: &[u8; 64]) -> [u8; 32] {
323 let mut a = [0u64; 8];
324 for i in 0..8 {
325 a[i] = u64::from_le_bytes(input[i * 8..(i + 1) * 8].try_into().unwrap());
326 }
327
328 let result = bn_mod(&a, 8);
329
330 let mut out = [0u8; 32];
331 for i in 0..4 {
332 out[i * 8..(i + 1) * 8].copy_from_slice(&result[i].to_le_bytes());
333 }
334 out
335}
336
337fn sc_add(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
339 let mut al = [0u64; 4];
340 let mut bl = [0u64; 4];
341 for i in 0..4 {
342 al[i] = u64::from_le_bytes(a[i * 8..(i + 1) * 8].try_into().unwrap());
343 bl[i] = u64::from_le_bytes(b[i * 8..(i + 1) * 8].try_into().unwrap());
344 }
345
346 let (r0, carry) = al[0].overflowing_add(bl[0]);
347 let (r1, carry) = adc(al[1], bl[1], carry);
348 let (r2, carry) = adc(al[2], bl[2], carry);
349 let (r3, carry) = adc(al[3], bl[3], carry);
350
351 let mut result = [r0, r1, r2, r3];
352
353 let (s0, borrow) = result[0].overflowing_sub(L[0]);
355 let (s1, borrow) = sbb(result[1], L[1], borrow);
356 let (s2, borrow) = sbb(result[2], L[2], borrow);
357 let (s3, borrow) = sbb(result[3], L[3], borrow);
358
359 let use_sub = carry | !borrow;
360 let mask = if use_sub { 0u64 } else { u64::MAX };
361 result[0] = (result[0] & mask) | (s0 & !mask);
362 result[1] = (result[1] & mask) | (s1 & !mask);
363 result[2] = (result[2] & mask) | (s2 & !mask);
364 result[3] = (result[3] & mask) | (s3 & !mask);
365
366 let mut out = [0u8; 32];
367 for i in 0..4 {
368 out[i * 8..(i + 1) * 8].copy_from_slice(&result[i].to_le_bytes());
369 }
370 out
371}
372
373fn sc_mul(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
375 let mut al = [0u64; 4];
376 let mut bl = [0u64; 4];
377 for i in 0..4 {
378 al[i] = u64::from_le_bytes(a[i * 8..(i + 1) * 8].try_into().unwrap());
379 bl[i] = u64::from_le_bytes(b[i * 8..(i + 1) * 8].try_into().unwrap());
380 }
381
382 let wide = mul256(al, bl);
383 let result = bn_mod(&wide, 8);
384
385 let mut out = [0u8; 32];
386 for i in 0..4 {
387 out[i * 8..(i + 1) * 8].copy_from_slice(&result[i].to_le_bytes());
388 }
389 out
390}
391
392fn bn_mod(a: &[u64], limbs: usize) -> [u64; 4] {
395 let mut r = [0u64; 5];
398
399 for word_idx in (0..limbs).rev() {
401 for bit_idx in (0..64).rev() {
402 let mut carry = 0u64;
404 for i in 0..5 {
405 let new_carry = r[i] >> 63;
406 r[i] = (r[i] << 1) | carry;
407 carry = new_carry;
408 }
409 r[0] |= (a[word_idx] >> bit_idx) & 1;
411
412 let (s0, b) = r[0].overflowing_sub(L[0]);
414 let (s1, b) = sbb(r[1], L[1], b);
415 let (s2, b) = sbb(r[2], L[2], b);
416 let (s3, b) = sbb(r[3], L[3], b);
417 let (s4, b) = sbb(r[4], 0, b);
418 if !b {
419 r[0] = s0;
420 r[1] = s1;
421 r[2] = s2;
422 r[3] = s3;
423 r[4] = s4;
424 }
425 }
426 }
427
428 [r[0], r[1], r[2], r[3]]
429}
430
431#[derive(Clone, Copy, Debug)]
437struct ExtPoint {
438 x: Fe25519,
439 y: Fe25519,
440 z: Fe25519,
441 t: Fe25519,
442}
443
444const D: Fe25519 = Fe25519([
447 0x75EB4DCA135978A3,
448 0x00700A4D4141D8AB,
449 0x8CC740797779E898,
450 0x52036CEE2B6FFE73,
451]);
452
453#[cfg(test)]
455const D2: Fe25519 = Fe25519([
456 0xEBD69B9426B2F159,
457 0x00E0149A8283B156,
458 0x198E80F2EEF3D130,
459 0x2406D9DC56DFFCE7,
460]);
461
462const B_X: Fe25519 = Fe25519([
465 0xC9562D608F25D51A,
466 0x692CC7609525A7B2,
467 0xC0A4E231FDD6DC5C,
468 0x216936D3CD6E53FE,
469]);
470
471const B_Y: Fe25519 = Fe25519([
474 0x6666666666666658,
475 0x6666666666666666,
476 0x6666666666666666,
477 0x6666666666666666,
478]);
479
480impl ExtPoint {
481 const IDENTITY: ExtPoint = ExtPoint {
482 x: Fe25519::ZERO,
483 y: Fe25519::ONE,
484 z: Fe25519::ONE,
485 t: Fe25519::ZERO,
486 };
487
488 fn from_affine(x: Fe25519, y: Fe25519) -> Self {
489 ExtPoint {
490 x,
491 y,
492 z: Fe25519::ONE,
493 t: x.mul(y),
494 }
495 }
496
497 fn basepoint() -> Self {
498 ExtPoint::from_affine(B_X, B_Y)
499 }
500
501 fn double(self) -> Self {
504 let a = self.x.square();
505 let b = self.y.square();
506 let c = self.z.square().add(self.z.square()); let d = a.neg(); let e = self.x.add(self.y).square().sub(a).sub(b);
509 let g = d.add(b);
510 let f = g.sub(c);
511 let h = d.sub(b);
512
513 ExtPoint {
514 x: e.mul(f),
515 y: g.mul(h),
516 t: e.mul(h),
517 z: f.mul(g),
518 }
519 }
520
521 fn add(self, other: Self) -> Self {
524 let a = self.x.mul(other.x);
525 let b = self.y.mul(other.y);
526 let c = self.t.mul(other.t).mul(D);
527 let dd = self.z.mul(other.z);
528
529 let e = (self.x.add(self.y)).mul(other.x.add(other.y)).sub(a).sub(b);
530 let f = dd.sub(c);
531 let g = dd.add(c);
532 let h = b.add(a); ExtPoint {
535 x: e.mul(f),
536 y: g.mul(h),
537 t: e.mul(h),
538 z: f.mul(g),
539 }
540 }
541
542 fn scalar_mul(self, scalar: &[u8; 32]) -> Self {
545 let mut result = ExtPoint::IDENTITY;
546 for byte_idx in (0..32).rev() {
547 for bit_idx in (0..8).rev() {
548 result = result.double();
549 let bit = (scalar[byte_idx] >> bit_idx) & 1;
550 let candidate = result.add(self);
551 result = ExtPoint::ct_select(result, candidate, bit);
552 }
553 }
554 result
555 }
556
557 fn ct_select(a: Self, b: Self, choice: u8) -> Self {
558 ExtPoint {
559 x: Fe25519::ct_select(a.x, b.x, choice),
560 y: Fe25519::ct_select(a.y, b.y, choice),
561 z: Fe25519::ct_select(a.z, b.z, choice),
562 t: Fe25519::ct_select(a.t, b.t, choice),
563 }
564 }
565
566 fn compress(self) -> [u8; 32] {
569 let z_inv = self.z.inv();
570 let x = self.x.mul(z_inv);
571 let y = self.y.mul(z_inv);
572 let mut bytes = y.to_bytes();
573 bytes[31] |= x.is_odd() << 7;
574 bytes
575 }
576
577 fn decompress(bytes: &[u8; 32]) -> Option<Self> {
579 let x_sign = (bytes[31] >> 7) & 1;
580 let mut y_bytes = *bytes;
581 y_bytes[31] &= 0x7F;
582 let y = Fe25519::from_bytes(&y_bytes);
583
584 let y2 = y.square();
586 let u = y2.sub(Fe25519::ONE); let v = D.mul(y2).add(Fe25519::ONE); let v3 = v.square().mul(v);
591 let v7 = v3.square().mul(v);
592 let uv7 = u.mul(v7);
593
594 let exp: [u64; 4] = [
596 0xFFFF_FFFF_FFFF_FFFD,
597 0xFFFF_FFFF_FFFF_FFFF,
598 0xFFFF_FFFF_FFFF_FFFF,
599 0x0FFF_FFFF_FFFF_FFFF,
600 ];
601 let uv7_pow = uv7.pow(exp);
602 let mut x = u.mul(v3).mul(uv7_pow);
603
604 let check = v.mul(x.square());
606 if check.equals(u) {
607 } else if check.equals(u.neg()) {
609 let sqrt_m1 = compute_sqrt_m1();
611 x = x.mul(sqrt_m1);
612 } else {
613 return None;
614 }
615
616 if x.is_zero() && x_sign == 1 {
617 return None;
618 }
619
620 if x.is_odd() != x_sign {
621 x = x.neg();
622 }
623
624 let t = x.mul(y);
625 Some(ExtPoint {
626 x,
627 y,
628 z: Fe25519::ONE,
629 t,
630 })
631 }
632
633 fn equals(self, other: Self) -> bool {
635 let lhs_x = self.x.mul(other.z);
636 let rhs_x = other.x.mul(self.z);
637 let lhs_y = self.y.mul(other.z);
638 let rhs_y = other.y.mul(self.z);
639 lhs_x.equals(rhs_x) && lhs_y.equals(rhs_y)
640 }
641}
642
643fn compute_sqrt_m1() -> Fe25519 {
645 let exp: [u64; 4] = [
647 0xFFFF_FFFF_FFFF_FFFB,
648 0xFFFF_FFFF_FFFF_FFFF,
649 0xFFFF_FFFF_FFFF_FFFF,
650 0x1FFF_FFFF_FFFF_FFFF,
651 ];
652 Fe25519::from_u64(2).pow(exp)
653}
654
655#[derive(Clone, Debug, PartialEq, Eq)]
661pub struct Ed25519PublicKey(pub [u8; 32]);
662
663#[derive(Clone)]
665pub struct Ed25519SecretKey(pub [u8; 32]);
666
667#[derive(Clone, Debug, PartialEq, Eq)]
669pub struct Ed25519Signature(pub [u8; 64]);
670
671pub fn ed25519_keygen(secret: &[u8; 32]) -> (Ed25519PublicKey, Ed25519SecretKey) {
675 let hash = Sha512::hash(secret);
676
677 let mut a = [0u8; 32];
678 a.copy_from_slice(&hash[..32]);
679 a[0] &= 248;
680 a[31] &= 127;
681 a[31] |= 64;
682
683 let big_a = ExtPoint::basepoint().scalar_mul(&a);
684 let pk_bytes = big_a.compress();
685
686 (Ed25519PublicKey(pk_bytes), Ed25519SecretKey(*secret))
687}
688
689fn update_dom2(hasher: &mut Sha512, dom2: Option<&[u8]>) {
712 if let Some(prefix) = dom2 {
713 hasher.update(prefix);
714 }
715}
716
717fn ed25519_sign_internal(sk: &Ed25519SecretKey, message_or_hash: &[u8], dom2: Option<&[u8]>) -> Ed25519Signature {
719 let hash = Sha512::hash(&sk.0);
720
721 let mut a = [0u8; 32];
722 a.copy_from_slice(&hash[..32]);
723 a[0] &= 248;
724 a[31] &= 127;
725 a[31] |= 64;
726
727 let prefix = &hash[32..64];
728
729 let big_a = ExtPoint::basepoint().scalar_mul(&a);
731 let pk_bytes = big_a.compress();
732
733 let mut hasher = Sha512::new();
735 update_dom2(&mut hasher, dom2);
736 hasher.update(prefix);
737 hasher.update(message_or_hash);
738 let r_hash = hasher.finalize();
739 let mut r_wide = [0u8; 64];
740 r_wide.copy_from_slice(&r_hash);
741 let r_scalar = sc_reduce(&r_wide);
742
743 let big_r = ExtPoint::basepoint().scalar_mul(&r_scalar);
745 let r_bytes = big_r.compress();
746
747 let mut hasher = Sha512::new();
749 update_dom2(&mut hasher, dom2);
750 hasher.update(&r_bytes);
751 hasher.update(&pk_bytes);
752 hasher.update(message_or_hash);
753 let k_hash = hasher.finalize();
754 let mut k_wide = [0u8; 64];
755 k_wide.copy_from_slice(&k_hash);
756 let k = sc_reduce(&k_wide);
757
758 let ka = sc_mul(&k, &a);
759 let s = sc_add(&r_scalar, &ka);
760
761 let mut sig = [0u8; 64];
762 sig[..32].copy_from_slice(&r_bytes);
763 sig[32..].copy_from_slice(&s);
764
765 Ed25519Signature(sig)
766}
767
768fn ed25519_verify_internal(
770 pk: &Ed25519PublicKey,
771 message_or_hash: &[u8],
772 sig: &Ed25519Signature,
773 dom2: Option<&[u8]>,
774) -> bool {
775 let r_bytes: [u8; 32] = match sig.0[..32].try_into() {
776 Ok(b) => b,
777 Err(_) => return false,
778 };
779 let big_r = match ExtPoint::decompress(&r_bytes) {
780 Some(p) => p,
781 None => return false,
782 };
783
784 let big_a = match ExtPoint::decompress(&pk.0) {
785 Some(p) => p,
786 None => return false,
787 };
788
789 let s_bytes: [u8; 32] = match sig.0[32..].try_into() {
790 Ok(b) => b,
791 Err(_) => return false,
792 };
793
794 {
796 let mut sl = [0u64; 4];
797 for i in 0..4 {
798 sl[i] = u64::from_le_bytes(s_bytes[i * 8..(i + 1) * 8].try_into().unwrap());
799 }
800 let (_, borrow) = sl[0].overflowing_sub(L[0]);
801 let (_, borrow) = sbb(sl[1], L[1], borrow);
802 let (_, borrow) = sbb(sl[2], L[2], borrow);
803 let (_, borrow) = sbb(sl[3], L[3], borrow);
804 if !borrow {
805 return false; }
807 }
808
809 let mut hasher = Sha512::new();
811 update_dom2(&mut hasher, dom2);
812 hasher.update(&r_bytes);
813 hasher.update(&pk.0);
814 hasher.update(message_or_hash);
815 let k_hash = hasher.finalize();
816 let mut k_wide = [0u8; 64];
817 k_wide.copy_from_slice(&k_hash);
818 let k = sc_reduce(&k_wide);
819
820 let sb = ExtPoint::basepoint().scalar_mul(&s_bytes);
822 let ka = big_a.scalar_mul(&k);
823 let rhs = big_r.add(ka);
824
825 let lhs = sb.double().double().double();
827 let rhs = rhs.double().double().double();
828
829 lhs.equals(rhs)
830}
831
832const DOM2_LITERAL: &[u8] = b"SigEd25519 no Ed25519 collisions";
843
844fn build_dom2(f: u8, context: &[u8]) -> Option<Vec<u8>> {
848 if context.len() > 255 {
849 return None;
850 }
851 let mut out = Vec::with_capacity(DOM2_LITERAL.len() + 2 + context.len());
852 out.extend_from_slice(DOM2_LITERAL);
853 out.push(f);
854 out.push(context.len() as u8);
855 out.extend_from_slice(context);
856 Some(out)
857}
858
859pub fn ed25519_sign(sk: &Ed25519SecretKey, msg: &[u8]) -> Ed25519Signature {
870 ed25519_sign_internal(sk, msg, None)
871}
872
873pub fn ed25519_verify(pk: &Ed25519PublicKey, msg: &[u8], sig: &Ed25519Signature) -> bool {
875 ed25519_verify_internal(pk, msg, sig, None)
876}
877
878pub fn ed25519ctx_sign(sk: &Ed25519SecretKey, msg: &[u8], context: &[u8]) -> Option<Ed25519Signature> {
896 if context.is_empty() {
897 return None;
898 }
899 let dom2 = build_dom2(0, context)?;
900 Some(ed25519_sign_internal(sk, msg, Some(&dom2)))
901}
902
903pub fn ed25519ctx_verify(pk: &Ed25519PublicKey, msg: &[u8], context: &[u8], sig: &Ed25519Signature) -> bool {
910 if context.is_empty() || context.len() > 255 {
911 return false;
912 }
913 let dom2 = match build_dom2(0, context) {
914 Some(d) => d,
915 None => return false,
916 };
917 ed25519_verify_internal(pk, msg, sig, Some(&dom2))
918}
919
920pub fn ed25519ph_sign(sk: &Ed25519SecretKey, msg: &[u8], context: &[u8]) -> Option<Ed25519Signature> {
939 let dom2 = build_dom2(1, context)?;
940 let m_prime = Sha512::hash(msg);
941 Some(ed25519_sign_internal(sk, &m_prime, Some(&dom2)))
942}
943
944pub fn ed25519ph_verify(pk: &Ed25519PublicKey, msg: &[u8], context: &[u8], sig: &Ed25519Signature) -> bool {
946 if context.len() > 255 {
947 return false;
948 }
949 let dom2 = match build_dom2(1, context) {
950 Some(d) => d,
951 None => return false,
952 };
953 let m_prime = Sha512::hash(msg);
954 ed25519_verify_internal(pk, &m_prime, sig, Some(&dom2))
955}
956
957pub fn ed25519ph_sign_prehashed(sk: &Ed25519SecretKey, prehashed: &[u8], context: &[u8]) -> Option<Ed25519Signature> {
965 if prehashed.len() != 64 {
966 return None;
967 }
968 let dom2 = build_dom2(1, context)?;
969 Some(ed25519_sign_internal(sk, prehashed, Some(&dom2)))
970}
971
972pub fn ed25519ph_verify_prehashed(
975 pk: &Ed25519PublicKey,
976 prehashed: &[u8],
977 context: &[u8],
978 sig: &Ed25519Signature,
979) -> bool {
980 if prehashed.len() != 64 || context.len() > 255 {
981 return false;
982 }
983 let dom2 = match build_dom2(1, context) {
984 Some(d) => d,
985 None => return false,
986 };
987 ed25519_verify_internal(pk, prehashed, sig, Some(&dom2))
988}
989
990#[cfg(test)]
1003mod tests {
1004 use super::*;
1005
1006 fn hex_to_bytes(s: &str) -> Vec<u8> {
1007 (0..s.len())
1008 .step_by(2)
1009 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
1010 .collect()
1011 }
1012
1013 #[test]
1014 fn test_fe25519_basic() {
1015 let a = Fe25519::ONE;
1016 let b = Fe25519::ONE;
1017 let c = a.add(b);
1018 assert_eq!(c.0[0], 2);
1019 assert_eq!(c.0[1], 0);
1020
1021 let d = c.sub(a);
1022 assert!(d.equals(Fe25519::ONE));
1023 }
1024
1025 #[test]
1026 fn test_fe25519_mul() {
1027 let a = Fe25519::from_u64(7);
1028 let b = Fe25519::from_u64(13);
1029 let c = a.mul(b);
1030 assert!(c.equals(Fe25519::from_u64(91)));
1031 }
1032
1033 #[test]
1034 fn test_fe25519_inv() {
1035 let a = Fe25519::from_u64(42);
1036 let b = a.inv();
1037 let c = a.mul(b);
1038 assert!(c.equals(Fe25519::ONE));
1039 }
1040
1041 #[test]
1042 fn test_basepoint_on_curve() {
1043 let x2 = B_X.square();
1045 let y2 = B_Y.square();
1046 let lhs = y2.sub(x2);
1047 let rhs = Fe25519::ONE.add(D.mul(x2).mul(y2));
1048 assert!(lhs.equals(rhs), "Base point not on curve!");
1049 }
1050
1051 #[test]
1052 fn test_d_constant() {
1053 let n = Fe25519::from_u64(121665).neg();
1055 let d_inv = Fe25519::from_u64(121666).inv();
1056 let d_computed = n.mul(d_inv);
1057 assert!(d_computed.equals(D), "D constant is wrong");
1058 }
1059
1060 #[test]
1061 fn test_d2_constant() {
1062 let d2_computed = D.add(D);
1063 assert!(d2_computed.equals(D2), "D2 constant is wrong");
1064 }
1065
1066 #[test]
1067 fn test_basepoint_compress_decompress() {
1068 let bp = ExtPoint::basepoint();
1069 let compressed = bp.compress();
1070 let decompressed = ExtPoint::decompress(&compressed).expect("decompress failed");
1071 assert!(bp.equals(decompressed));
1072 }
1073
1074 fn naive_scalar_mul(p: ExtPoint, scalar: &[u8; 32]) -> ExtPoint {
1075 let mut acc = ExtPoint::IDENTITY;
1078 let mut started = false;
1079 for byte_idx in (0..32).rev() {
1080 for bit_idx in (0..8).rev() {
1081 if started {
1082 acc = acc.double();
1083 }
1084 let bit = (scalar[byte_idx] >> bit_idx) & 1;
1085 if bit == 1 {
1086 if !started {
1087 acc = p;
1088 started = true;
1089 } else {
1090 acc = acc.add(p);
1091 }
1092 }
1093 }
1094 }
1095 acc
1096 }
1097
1098 #[test]
1099 fn test_scalar_mul_vs_naive() {
1100 let bp = ExtPoint::basepoint();
1101 let mut s = [0u8; 32];
1102 for i in 0..32 {
1104 s[i] = (i as u8) ^ 0xa5;
1105 }
1106 s[31] &= 0x7f;
1107 let r1 = bp.scalar_mul(&s);
1108 let r2 = naive_scalar_mul(bp, &s);
1109 assert!(r1.equals(r2));
1110 }
1111
1112 #[test]
1113 fn test_sc_reduce_basic() {
1114 let mut x = [0u8; 64];
1116 x[0] = 1;
1117 let r = sc_reduce(&x);
1118 assert_eq!(r[0], 1);
1119 for i in 1..32 {
1120 assert_eq!(r[i], 0);
1121 }
1122
1123 let mut x = [0u8; 64];
1125 x[0..8].copy_from_slice(&L[0].to_le_bytes());
1126 x[8..16].copy_from_slice(&L[1].to_le_bytes());
1127 x[16..24].copy_from_slice(&L[2].to_le_bytes());
1128 x[24..32].copy_from_slice(&L[3].to_le_bytes());
1129 let r = sc_reduce(&x);
1130 for i in 0..32 {
1131 assert_eq!(r[i], 0, "L mod L should be 0, byte {}", i);
1132 }
1133
1134 let mut x = [0u8; 64];
1136 x[0..8].copy_from_slice(&(L[0] + 1).to_le_bytes());
1137 x[8..16].copy_from_slice(&L[1].to_le_bytes());
1138 x[16..24].copy_from_slice(&L[2].to_le_bytes());
1139 x[24..32].copy_from_slice(&L[3].to_le_bytes());
1140 let r = sc_reduce(&x);
1141 assert_eq!(r[0], 1);
1142 }
1143
1144 #[test]
1145 fn test_fe_pow_fermat() {
1146 let a = Fe25519::from_u64(7);
1148 let pm1: [u64; 4] = [
1149 0xFFFF_FFFF_FFFF_FFEC,
1150 0xFFFF_FFFF_FFFF_FFFF,
1151 0xFFFF_FFFF_FFFF_FFFF,
1152 0x7FFF_FFFF_FFFF_FFFF,
1153 ];
1154 let r = a.pow(pm1);
1155 assert!(r.equals(Fe25519::ONE));
1156 }
1157
1158 #[test]
1159 fn test_scalar_mul_two() {
1160 let bp = ExtPoint::basepoint();
1161 let mut two = [0u8; 32];
1162 two[0] = 2;
1163 let r = bp.scalar_mul(&two);
1164 assert!(r.equals(bp.double()));
1165 }
1166
1167 #[test]
1168 fn test_scalar_mul_three() {
1169 let bp = ExtPoint::basepoint();
1170 let mut three = [0u8; 32];
1171 three[0] = 3;
1172 let r = bp.scalar_mul(&three);
1173 assert!(r.equals(bp.double().add(bp)));
1174 }
1175
1176 #[test]
1177 fn test_scalar_mul_identity() {
1178 let bp = ExtPoint::basepoint();
1179 let mut one = [0u8; 32];
1180 one[0] = 1;
1181 let result = bp.scalar_mul(&one);
1182 assert!(result.equals(bp));
1183 }
1184
1185 #[test]
1186 fn test_point_add_double() {
1187 let bp = ExtPoint::basepoint();
1188 let bp2_add = bp.add(bp);
1189 let bp2_dbl = bp.double();
1190 assert!(bp2_add.equals(bp2_dbl));
1191 }
1192
1193 #[test]
1195 fn test_ed25519_vector1() {
1196 let sk_hex = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60";
1197 let pk_hex = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
1198 let sig_hex = "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155\
1199 5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b";
1200
1201 let sk_bytes = hex_to_bytes(sk_hex);
1202 let pk_bytes = hex_to_bytes(pk_hex);
1203 let sig_bytes = hex_to_bytes(sig_hex);
1204
1205 let mut sk = [0u8; 32];
1206 sk.copy_from_slice(&sk_bytes);
1207
1208 let (pk, secret) = ed25519_keygen(&sk);
1209 assert_eq!(&pk.0[..], &pk_bytes[..], "Public key mismatch");
1210
1211 let signature = ed25519_sign(&secret, b"");
1212 assert_eq!(&signature.0[..], &sig_bytes[..], "Signature mismatch");
1213
1214 assert!(ed25519_verify(&pk, b"", &signature), "Verification failed");
1215 }
1216
1217 #[test]
1219 fn test_ed25519_vector2() {
1220 let sk_hex = "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb";
1221 let pk_hex = "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c";
1222 let sig_hex = "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da\
1223 085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00";
1224
1225 let sk_bytes = hex_to_bytes(sk_hex);
1226 let pk_bytes = hex_to_bytes(pk_hex);
1227 let sig_bytes = hex_to_bytes(sig_hex);
1228
1229 let mut sk = [0u8; 32];
1230 sk.copy_from_slice(&sk_bytes);
1231
1232 let (pk, secret) = ed25519_keygen(&sk);
1233 assert_eq!(&pk.0[..], &pk_bytes[..], "Public key mismatch");
1234
1235 let msg = [0x72u8];
1236 let signature = ed25519_sign(&secret, &msg);
1237 assert_eq!(&signature.0[..], &sig_bytes[..], "Signature mismatch");
1238
1239 assert!(ed25519_verify(&pk, &msg, &signature), "Verification failed");
1240 }
1241
1242 #[test]
1251 fn rfc8032_section_7_2_ed25519ctx_vector() {
1252 let sk_bytes = hex_to_bytes("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6");
1253 let pk_bytes = hex_to_bytes("dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292");
1254 let msg = hex_to_bytes("f726936d19c800494e3fdaff20b276a8");
1255 let context = hex_to_bytes("666f6f"); let sig_bytes = hex_to_bytes(
1257 "55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a\
1258 8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d",
1259 );
1260
1261 let mut sk_arr = [0u8; 32];
1262 sk_arr.copy_from_slice(&sk_bytes);
1263 let (pk, secret) = ed25519_keygen(&sk_arr);
1264 assert_eq!(pk.0.as_slice(), pk_bytes.as_slice(), "pk mismatch");
1265
1266 let signature = ed25519ctx_sign(&secret, &msg, &context).expect("ctx_sign");
1268 assert_eq!(
1269 signature.0.as_slice(),
1270 sig_bytes.as_slice(),
1271 "Ed25519ctx signature mismatch"
1272 );
1273
1274 assert!(ed25519ctx_verify(&pk, &msg, &context, &signature));
1276 }
1277
1278 #[test]
1287 fn rfc8032_section_7_3_ed25519ph_vector() {
1288 let sk_bytes = hex_to_bytes("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42");
1289 let pk_bytes = hex_to_bytes("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf");
1290 let msg = hex_to_bytes("616263"); let sig_bytes = hex_to_bytes(
1292 "98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae41\
1293 31f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406",
1294 );
1295
1296 let mut sk_arr = [0u8; 32];
1297 sk_arr.copy_from_slice(&sk_bytes);
1298 let (pk, secret) = ed25519_keygen(&sk_arr);
1299 assert_eq!(pk.0.as_slice(), pk_bytes.as_slice(), "pk mismatch");
1300
1301 let signature = ed25519ph_sign(&secret, &msg, b"").expect("ph_sign");
1303 assert_eq!(
1304 signature.0.as_slice(),
1305 sig_bytes.as_slice(),
1306 "Ed25519ph signature mismatch"
1307 );
1308
1309 assert!(ed25519ph_verify(&pk, &msg, b"", &signature));
1310 }
1311
1312 #[test]
1316 fn ed25519ph_prehashed_matches_message_form() {
1317 let sk_bytes = hex_to_bytes("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42");
1318 let mut sk_arr = [0u8; 32];
1319 sk_arr.copy_from_slice(&sk_bytes);
1320 let (pk, secret) = ed25519_keygen(&sk_arr);
1321
1322 let from_msg = ed25519ph_sign(&secret, b"abc", b"").expect("ph_sign");
1323
1324 let digest = Sha512::hash(b"abc");
1326 let from_digest = ed25519ph_sign_prehashed(&secret, &digest, b"").expect("ph_sign_prehashed");
1327
1328 assert_eq!(from_msg.0, from_digest.0);
1329
1330 assert!(ed25519ph_verify(&pk, b"abc", b"", &from_msg));
1332 assert!(ed25519ph_verify_prehashed(&pk, &digest, b"", &from_msg));
1333 }
1334
1335 fn make_test_keys() -> (Ed25519PublicKey, Ed25519SecretKey) {
1345 let sk_bytes = hex_to_bytes("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6");
1346 let mut sk = [0u8; 32];
1347 sk.copy_from_slice(&sk_bytes);
1348 ed25519_keygen(&sk)
1349 }
1350
1351 #[test]
1352 fn ed25519ctx_requires_nonempty_context() {
1353 let (_pk, sk) = make_test_keys();
1354 assert!(ed25519ctx_sign(&sk, b"any message", b"").is_none());
1356 }
1357
1358 #[test]
1359 fn ed25519ctx_signature_does_not_verify_as_pure() {
1360 let (pk, sk) = make_test_keys();
1361 let msg = b"shared message";
1362 let sig = ed25519ctx_sign(&sk, msg, b"appA").expect("ctx_sign");
1363 assert!(!ed25519_verify(&pk, msg, &sig));
1366 }
1367
1368 #[test]
1369 fn pure_signature_does_not_verify_as_ctx() {
1370 let (pk, sk) = make_test_keys();
1371 let msg = b"shared message";
1372 let sig = ed25519_sign(&sk, msg);
1373 assert!(!ed25519ctx_verify(&pk, msg, b"appA", &sig));
1376 }
1377
1378 #[test]
1379 fn ed25519ctx_different_contexts_dont_cross() {
1380 let (pk, sk) = make_test_keys();
1381 let msg = b"shared message";
1382 let sig_a = ed25519ctx_sign(&sk, msg, b"appA").expect("ctx_sign A");
1383 let sig_b = ed25519ctx_sign(&sk, msg, b"appB").expect("ctx_sign B");
1384
1385 assert!(ed25519ctx_verify(&pk, msg, b"appA", &sig_a));
1387 assert!(ed25519ctx_verify(&pk, msg, b"appB", &sig_b));
1388
1389 assert!(!ed25519ctx_verify(&pk, msg, b"appB", &sig_a));
1391 assert!(!ed25519ctx_verify(&pk, msg, b"appA", &sig_b));
1392
1393 assert_ne!(sig_a.0, sig_b.0);
1396 }
1397
1398 #[test]
1399 fn ed25519ph_signature_does_not_verify_as_pure() {
1400 let (pk, sk) = make_test_keys();
1401 let msg = b"shared message";
1402 let sig = ed25519ph_sign(&sk, msg, b"").expect("ph_sign");
1403 assert!(!ed25519_verify(&pk, msg, &sig));
1406 }
1407
1408 #[test]
1409 fn ed25519ph_signature_does_not_verify_as_ctx() {
1410 let (pk, sk) = make_test_keys();
1411 let msg = b"shared message";
1412 let sig = ed25519ph_sign(&sk, msg, b"context").expect("ph_sign");
1413 assert!(!ed25519ctx_verify(&pk, msg, b"context", &sig));
1416 }
1417
1418 #[test]
1419 fn ed25519ctx_max_context_length() {
1420 let (pk, sk) = make_test_keys();
1421 let msg = b"x";
1422 let ctx_max = vec![0xa5u8; 255];
1424 let sig = ed25519ctx_sign(&sk, msg, &ctx_max).expect("ctx max len");
1425 assert!(ed25519ctx_verify(&pk, msg, &ctx_max, &sig));
1426
1427 let ctx_too_long = vec![0xa5u8; 256];
1430 assert!(ed25519ctx_sign(&sk, msg, &ctx_too_long).is_none());
1431 assert!(!ed25519ctx_verify(&pk, msg, &ctx_too_long, &sig));
1432 }
1433}