1use crate::Hasher;
55use crate::hash::sha512::Sha512;
56
57#[derive(Clone, Copy, Debug)]
63struct Fe25519([u64; 4]);
64
65const P: [u64; 4] = [
67 0xFFFF_FFFF_FFFF_FFED,
68 0xFFFF_FFFF_FFFF_FFFF,
69 0xFFFF_FFFF_FFFF_FFFF,
70 0x7FFF_FFFF_FFFF_FFFF,
71];
72
73impl Fe25519 {
74 const ZERO: Fe25519 = Fe25519([0, 0, 0, 0]);
75 const ONE: Fe25519 = Fe25519([1, 0, 0, 0]);
76
77 fn reduce(mut limbs: [u64; 4]) -> Self {
79 let (r0, borrow) = limbs[0].overflowing_sub(P[0]);
81 let (r1, borrow) = sbb(limbs[1], P[1], borrow);
82 let (r2, borrow) = sbb(limbs[2], P[2], borrow);
83 let (r3, borrow) = sbb(limbs[3], P[3], borrow);
84
85 let mask = if borrow { u64::MAX } else { 0 };
87 limbs[0] = (limbs[0] & mask) | (r0 & !mask);
88 limbs[1] = (limbs[1] & mask) | (r1 & !mask);
89 limbs[2] = (limbs[2] & mask) | (r2 & !mask);
90 limbs[3] = (limbs[3] & mask) | (r3 & !mask);
91
92 Fe25519(limbs)
93 }
94
95 fn add(self, rhs: Self) -> Self {
96 let (r0, carry) = self.0[0].overflowing_add(rhs.0[0]);
97 let (r1, carry) = adc(self.0[1], rhs.0[1], carry);
98 let (r2, carry) = adc(self.0[2], rhs.0[2], carry);
99 let (r3, _carry) = adc(self.0[3], rhs.0[3], carry);
100 Fe25519::reduce([r0, r1, r2, r3])
101 }
102
103 fn sub(self, rhs: Self) -> Self {
104 let (r0, borrow) = self.0[0].overflowing_sub(rhs.0[0]);
105 let (r1, borrow) = sbb(self.0[1], rhs.0[1], borrow);
106 let (r2, borrow) = sbb(self.0[2], rhs.0[2], borrow);
107 let (r3, borrow) = sbb(self.0[3], rhs.0[3], borrow);
108
109 let mask = if borrow { u64::MAX } else { 0 };
111 let (r0, carry) = r0.overflowing_add(P[0] & mask);
112 let (r1, carry) = adc(r1, P[1] & mask, carry);
113 let (r2, carry) = adc(r2, P[2] & mask, carry);
114 let (r3, _) = adc(r3, P[3] & mask, carry);
115
116 Fe25519([r0, r1, r2, r3])
117 }
118
119 fn neg(self) -> Self {
120 Fe25519::ZERO.sub(self)
121 }
122
123 fn mul(self, rhs: Self) -> Self {
125 let wide = mul256(self.0, rhs.0);
126 fe_reduce_wide(wide)
127 }
128
129 fn square(self) -> Self {
130 self.mul(self)
131 }
132
133 fn pow(self, exp: [u64; 4]) -> Self {
135 let mut result = Fe25519::ONE;
136 let mut base = self;
137 for i in 0..4 {
138 let mut e = exp[i];
139 for _ in 0..64 {
140 if e & 1 == 1 {
141 result = result.mul(base);
142 }
143 base = base.square();
144 e >>= 1;
145 }
146 }
147 result
148 }
149
150 fn inv(self) -> Self {
152 let pm2: [u64; 4] = [
154 0xFFFF_FFFF_FFFF_FFEB,
155 0xFFFF_FFFF_FFFF_FFFF,
156 0xFFFF_FFFF_FFFF_FFFF,
157 0x7FFF_FFFF_FFFF_FFFF,
158 ];
159 self.pow(pm2)
160 }
161
162 fn equals(self, other: Self) -> bool {
164 let a = Fe25519::reduce(self.0);
165 let b = Fe25519::reduce(other.0);
166 let mut acc = 0u64;
167 for i in 0..4 {
168 acc |= a.0[i] ^ b.0[i];
169 }
170 acc == 0
171 }
172
173 fn is_zero(self) -> bool {
174 self.equals(Fe25519::ZERO)
175 }
176
177 fn to_bytes(self) -> [u8; 32] {
179 let r = Fe25519::reduce(self.0);
180 let mut out = [0u8; 32];
181 out[0..8].copy_from_slice(&r.0[0].to_le_bytes());
182 out[8..16].copy_from_slice(&r.0[1].to_le_bytes());
183 out[16..24].copy_from_slice(&r.0[2].to_le_bytes());
184 out[24..32].copy_from_slice(&r.0[3].to_le_bytes());
185 out
186 }
187
188 fn from_bytes(bytes: &[u8; 32]) -> Self {
190 let mut limbs = [0u64; 4];
191 limbs[0] = u64::from_le_bytes(bytes[0..8].try_into().unwrap());
192 limbs[1] = u64::from_le_bytes(bytes[8..16].try_into().unwrap());
193 limbs[2] = u64::from_le_bytes(bytes[16..24].try_into().unwrap());
194 limbs[3] = u64::from_le_bytes(bytes[24..32].try_into().unwrap());
195 limbs[3] &= 0x7FFF_FFFF_FFFF_FFFF;
196 Fe25519::reduce(limbs)
197 }
198
199 fn from_u64(v: u64) -> Self {
200 Fe25519([v, 0, 0, 0])
201 }
202
203 fn is_odd(self) -> u8 {
205 let r = Fe25519::reduce(self.0);
206 (r.0[0] & 1) as u8
207 }
208
209 fn ct_select(a: Self, b: Self, choice: u8) -> Self {
211 let mask = (choice as u64).wrapping_neg();
212 Fe25519([
213 a.0[0] ^ (mask & (a.0[0] ^ b.0[0])),
214 a.0[1] ^ (mask & (a.0[1] ^ b.0[1])),
215 a.0[2] ^ (mask & (a.0[2] ^ b.0[2])),
216 a.0[3] ^ (mask & (a.0[3] ^ b.0[3])),
217 ])
218 }
219}
220
221#[inline(always)]
224fn adc(a: u64, b: u64, carry_in: bool) -> (u64, bool) {
225 let (s1, c1) = a.overflowing_add(b);
226 let (s2, c2) = s1.overflowing_add(carry_in as u64);
227 (s2, c1 | c2)
228}
229
230#[inline(always)]
231fn sbb(a: u64, b: u64, borrow_in: bool) -> (u64, bool) {
232 let (s1, b1) = a.overflowing_sub(b);
233 let (s2, b2) = s1.overflowing_sub(borrow_in as u64);
234 (s2, b1 | b2)
235}
236
237#[inline(always)]
238fn mul64(a: u64, b: u64) -> u128 {
239 (a as u128) * (b as u128)
240}
241
242fn mul256(a: [u64; 4], b: [u64; 4]) -> [u64; 8] {
244 let mut r = [0u64; 8];
245 for i in 0..4 {
246 let mut carry = 0u64;
247 for j in 0..4 {
248 let uv = mul64(a[i], b[j]) + r[i + j] as u128 + carry as u128;
249 r[i + j] = uv as u64;
250 carry = (uv >> 64) as u64;
251 }
252 r[i + 4] = carry;
253 }
254 r
255}
256
257fn fe_reduce_wide(w: [u64; 8]) -> Fe25519 {
261 let low3_top_bit = (w[3] >> 63) & 1;
263 let low = [w[0], w[1], w[2], w[3] & 0x7FFF_FFFF_FFFF_FFFF];
264
265 let high = [
267 (w[4] << 1) | low3_top_bit,
268 (w[5] << 1) | (w[4] >> 63),
269 (w[6] << 1) | (w[5] >> 63),
270 (w[7] << 1) | (w[6] >> 63),
271 w[7] >> 63,
272 ];
273
274 let mut acc = [0u64; 5];
276 let mut carry = 0u128;
277 for i in 0..5 {
278 carry += low.get(i).copied().unwrap_or(0) as u128 + 19u128 * high[i] as u128;
279 acc[i] = carry as u64;
280 carry >>= 64;
281 }
282
283 let top_bit = (acc[3] >> 63) & 1;
285 acc[3] &= 0x7FFF_FFFF_FFFF_FFFF;
286 let extra = (acc[4] << 1) | top_bit;
287
288 let add = extra as u128 * 19;
290 let (r0, c) = acc[0].overflowing_add(add as u64);
291 let (r1, c) = adc(acc[1], (add >> 64) as u64, c);
292 let (r2, c) = adc(acc[2], 0, c);
293 let (r3, _) = adc(acc[3], 0, c);
294
295 Fe25519::reduce([r0, r1, r2, r3])
296}
297
298const L: [u64; 4] = [
304 0x5812631A5CF5D3ED,
305 0x14DEF9DEA2F79CD6,
306 0x0000000000000000,
307 0x1000000000000000,
308];
309
310fn sc_reduce(input: &[u8; 64]) -> [u8; 32] {
312 let mut a = [0u64; 8];
313 for i in 0..8 {
314 a[i] = u64::from_le_bytes(input[i * 8..(i + 1) * 8].try_into().unwrap());
315 }
316
317 let result = bn_mod(&a, 8);
318
319 let mut out = [0u8; 32];
320 for i in 0..4 {
321 out[i * 8..(i + 1) * 8].copy_from_slice(&result[i].to_le_bytes());
322 }
323 out
324}
325
326fn sc_add(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
328 let mut al = [0u64; 4];
329 let mut bl = [0u64; 4];
330 for i in 0..4 {
331 al[i] = u64::from_le_bytes(a[i * 8..(i + 1) * 8].try_into().unwrap());
332 bl[i] = u64::from_le_bytes(b[i * 8..(i + 1) * 8].try_into().unwrap());
333 }
334
335 let (r0, carry) = al[0].overflowing_add(bl[0]);
336 let (r1, carry) = adc(al[1], bl[1], carry);
337 let (r2, carry) = adc(al[2], bl[2], carry);
338 let (r3, carry) = adc(al[3], bl[3], carry);
339
340 let mut result = [r0, r1, r2, r3];
341
342 let (s0, borrow) = result[0].overflowing_sub(L[0]);
344 let (s1, borrow) = sbb(result[1], L[1], borrow);
345 let (s2, borrow) = sbb(result[2], L[2], borrow);
346 let (s3, borrow) = sbb(result[3], L[3], borrow);
347
348 let use_sub = carry | !borrow;
349 let mask = if use_sub { 0u64 } else { u64::MAX };
350 result[0] = (result[0] & mask) | (s0 & !mask);
351 result[1] = (result[1] & mask) | (s1 & !mask);
352 result[2] = (result[2] & mask) | (s2 & !mask);
353 result[3] = (result[3] & mask) | (s3 & !mask);
354
355 let mut out = [0u8; 32];
356 for i in 0..4 {
357 out[i * 8..(i + 1) * 8].copy_from_slice(&result[i].to_le_bytes());
358 }
359 out
360}
361
362fn sc_mul(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
364 let mut al = [0u64; 4];
365 let mut bl = [0u64; 4];
366 for i in 0..4 {
367 al[i] = u64::from_le_bytes(a[i * 8..(i + 1) * 8].try_into().unwrap());
368 bl[i] = u64::from_le_bytes(b[i * 8..(i + 1) * 8].try_into().unwrap());
369 }
370
371 let wide = mul256(al, bl);
372 let result = bn_mod(&wide, 8);
373
374 let mut out = [0u8; 32];
375 for i in 0..4 {
376 out[i * 8..(i + 1) * 8].copy_from_slice(&result[i].to_le_bytes());
377 }
378 out
379}
380
381fn bn_mod(a: &[u64], limbs: usize) -> [u64; 4] {
384 let mut r = [0u64; 5];
387
388 for word_idx in (0..limbs).rev() {
390 for bit_idx in (0..64).rev() {
391 let mut carry = 0u64;
393 for i in 0..5 {
394 let new_carry = r[i] >> 63;
395 r[i] = (r[i] << 1) | carry;
396 carry = new_carry;
397 }
398 r[0] |= (a[word_idx] >> bit_idx) & 1;
400
401 let (s0, b) = r[0].overflowing_sub(L[0]);
403 let (s1, b) = sbb(r[1], L[1], b);
404 let (s2, b) = sbb(r[2], L[2], b);
405 let (s3, b) = sbb(r[3], L[3], b);
406 let (s4, b) = sbb(r[4], 0, b);
407 if !b {
408 r[0] = s0;
409 r[1] = s1;
410 r[2] = s2;
411 r[3] = s3;
412 r[4] = s4;
413 }
414 }
415 }
416
417 [r[0], r[1], r[2], r[3]]
418}
419
420#[derive(Clone, Copy, Debug)]
426struct ExtPoint {
427 x: Fe25519,
428 y: Fe25519,
429 z: Fe25519,
430 t: Fe25519,
431}
432
433const D: Fe25519 = Fe25519([
436 0x75EB4DCA135978A3,
437 0x00700A4D4141D8AB,
438 0x8CC740797779E898,
439 0x52036CEE2B6FFE73,
440]);
441
442#[cfg(test)]
444const D2: Fe25519 = Fe25519([
445 0xEBD69B9426B2F159,
446 0x00E0149A8283B156,
447 0x198E80F2EEF3D130,
448 0x2406D9DC56DFFCE7,
449]);
450
451const B_X: Fe25519 = Fe25519([
454 0xC9562D608F25D51A,
455 0x692CC7609525A7B2,
456 0xC0A4E231FDD6DC5C,
457 0x216936D3CD6E53FE,
458]);
459
460const B_Y: Fe25519 = Fe25519([
463 0x6666666666666658,
464 0x6666666666666666,
465 0x6666666666666666,
466 0x6666666666666666,
467]);
468
469impl ExtPoint {
470 const IDENTITY: ExtPoint = ExtPoint {
471 x: Fe25519::ZERO,
472 y: Fe25519::ONE,
473 z: Fe25519::ONE,
474 t: Fe25519::ZERO,
475 };
476
477 fn from_affine(x: Fe25519, y: Fe25519) -> Self {
478 ExtPoint {
479 x,
480 y,
481 z: Fe25519::ONE,
482 t: x.mul(y),
483 }
484 }
485
486 fn basepoint() -> Self {
487 ExtPoint::from_affine(B_X, B_Y)
488 }
489
490 fn double(self) -> Self {
493 let a = self.x.square();
494 let b = self.y.square();
495 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);
498 let g = d.add(b);
499 let f = g.sub(c);
500 let h = d.sub(b);
501
502 ExtPoint {
503 x: e.mul(f),
504 y: g.mul(h),
505 t: e.mul(h),
506 z: f.mul(g),
507 }
508 }
509
510 fn add(self, other: Self) -> Self {
513 let a = self.x.mul(other.x);
514 let b = self.y.mul(other.y);
515 let c = self.t.mul(other.t).mul(D);
516 let dd = self.z.mul(other.z);
517
518 let e = (self.x.add(self.y)).mul(other.x.add(other.y)).sub(a).sub(b);
519 let f = dd.sub(c);
520 let g = dd.add(c);
521 let h = b.add(a); ExtPoint {
524 x: e.mul(f),
525 y: g.mul(h),
526 t: e.mul(h),
527 z: f.mul(g),
528 }
529 }
530
531 fn scalar_mul(self, scalar: &[u8; 32]) -> Self {
534 let mut result = ExtPoint::IDENTITY;
535 for byte_idx in (0..32).rev() {
536 for bit_idx in (0..8).rev() {
537 result = result.double();
538 let bit = (scalar[byte_idx] >> bit_idx) & 1;
539 let candidate = result.add(self);
540 result = ExtPoint::ct_select(result, candidate, bit);
541 }
542 }
543 result
544 }
545
546 fn ct_select(a: Self, b: Self, choice: u8) -> Self {
547 ExtPoint {
548 x: Fe25519::ct_select(a.x, b.x, choice),
549 y: Fe25519::ct_select(a.y, b.y, choice),
550 z: Fe25519::ct_select(a.z, b.z, choice),
551 t: Fe25519::ct_select(a.t, b.t, choice),
552 }
553 }
554
555 fn compress(self) -> [u8; 32] {
558 let z_inv = self.z.inv();
559 let x = self.x.mul(z_inv);
560 let y = self.y.mul(z_inv);
561 let mut bytes = y.to_bytes();
562 bytes[31] |= x.is_odd() << 7;
563 bytes
564 }
565
566 fn decompress(bytes: &[u8; 32]) -> Option<Self> {
568 let x_sign = (bytes[31] >> 7) & 1;
569 let mut y_bytes = *bytes;
570 y_bytes[31] &= 0x7F;
571 let y = Fe25519::from_bytes(&y_bytes);
572
573 let y2 = y.square();
575 let u = y2.sub(Fe25519::ONE); let v = D.mul(y2).add(Fe25519::ONE); let v3 = v.square().mul(v);
580 let v7 = v3.square().mul(v);
581 let uv7 = u.mul(v7);
582
583 let exp: [u64; 4] = [
585 0xFFFF_FFFF_FFFF_FFFD,
586 0xFFFF_FFFF_FFFF_FFFF,
587 0xFFFF_FFFF_FFFF_FFFF,
588 0x0FFF_FFFF_FFFF_FFFF,
589 ];
590 let uv7_pow = uv7.pow(exp);
591 let mut x = u.mul(v3).mul(uv7_pow);
592
593 let check = v.mul(x.square());
595 if check.equals(u) {
596 } else if check.equals(u.neg()) {
598 let sqrt_m1 = compute_sqrt_m1();
600 x = x.mul(sqrt_m1);
601 } else {
602 return None;
603 }
604
605 if x.is_zero() && x_sign == 1 {
606 return None;
607 }
608
609 if x.is_odd() != x_sign {
610 x = x.neg();
611 }
612
613 let t = x.mul(y);
614 Some(ExtPoint {
615 x,
616 y,
617 z: Fe25519::ONE,
618 t,
619 })
620 }
621
622 fn equals(self, other: Self) -> bool {
624 let lhs_x = self.x.mul(other.z);
625 let rhs_x = other.x.mul(self.z);
626 let lhs_y = self.y.mul(other.z);
627 let rhs_y = other.y.mul(self.z);
628 lhs_x.equals(rhs_x) && lhs_y.equals(rhs_y)
629 }
630}
631
632fn compute_sqrt_m1() -> Fe25519 {
634 let exp: [u64; 4] = [
636 0xFFFF_FFFF_FFFF_FFFB,
637 0xFFFF_FFFF_FFFF_FFFF,
638 0xFFFF_FFFF_FFFF_FFFF,
639 0x1FFF_FFFF_FFFF_FFFF,
640 ];
641 Fe25519::from_u64(2).pow(exp)
642}
643
644#[derive(Clone, Debug, PartialEq, Eq)]
650pub struct Ed25519PublicKey(pub [u8; 32]);
651
652#[derive(Clone)]
654pub struct Ed25519SecretKey(pub [u8; 32]);
655
656#[derive(Clone, Debug, PartialEq, Eq)]
658pub struct Ed25519Signature(pub [u8; 64]);
659
660pub fn ed25519_keygen(secret: &[u8; 32]) -> (Ed25519PublicKey, Ed25519SecretKey) {
664 let hash = Sha512::hash(secret);
665
666 let mut a = [0u8; 32];
667 a.copy_from_slice(&hash[..32]);
668 a[0] &= 248;
669 a[31] &= 127;
670 a[31] |= 64;
671
672 let big_a = ExtPoint::basepoint().scalar_mul(&a);
673 let pk_bytes = big_a.compress();
674
675 (Ed25519PublicKey(pk_bytes), Ed25519SecretKey(*secret))
676}
677
678fn update_dom2(hasher: &mut Sha512, dom2: Option<&[u8]>) {
701 if let Some(prefix) = dom2 {
702 hasher.update(prefix);
703 }
704}
705
706fn ed25519_sign_internal(sk: &Ed25519SecretKey, message_or_hash: &[u8], dom2: Option<&[u8]>) -> Ed25519Signature {
708 let hash = Sha512::hash(&sk.0);
709
710 let mut a = [0u8; 32];
711 a.copy_from_slice(&hash[..32]);
712 a[0] &= 248;
713 a[31] &= 127;
714 a[31] |= 64;
715
716 let prefix = &hash[32..64];
717
718 let big_a = ExtPoint::basepoint().scalar_mul(&a);
720 let pk_bytes = big_a.compress();
721
722 let mut hasher = Sha512::new();
724 update_dom2(&mut hasher, dom2);
725 hasher.update(prefix);
726 hasher.update(message_or_hash);
727 let r_hash = hasher.finalize();
728 let mut r_wide = [0u8; 64];
729 r_wide.copy_from_slice(&r_hash);
730 let r_scalar = sc_reduce(&r_wide);
731
732 let big_r = ExtPoint::basepoint().scalar_mul(&r_scalar);
734 let r_bytes = big_r.compress();
735
736 let mut hasher = Sha512::new();
738 update_dom2(&mut hasher, dom2);
739 hasher.update(&r_bytes);
740 hasher.update(&pk_bytes);
741 hasher.update(message_or_hash);
742 let k_hash = hasher.finalize();
743 let mut k_wide = [0u8; 64];
744 k_wide.copy_from_slice(&k_hash);
745 let k = sc_reduce(&k_wide);
746
747 let ka = sc_mul(&k, &a);
748 let s = sc_add(&r_scalar, &ka);
749
750 let mut sig = [0u8; 64];
751 sig[..32].copy_from_slice(&r_bytes);
752 sig[32..].copy_from_slice(&s);
753
754 Ed25519Signature(sig)
755}
756
757fn ed25519_verify_internal(
759 pk: &Ed25519PublicKey,
760 message_or_hash: &[u8],
761 sig: &Ed25519Signature,
762 dom2: Option<&[u8]>,
763) -> bool {
764 let r_bytes: [u8; 32] = match sig.0[..32].try_into() {
765 Ok(b) => b,
766 Err(_) => return false,
767 };
768 let big_r = match ExtPoint::decompress(&r_bytes) {
769 Some(p) => p,
770 None => return false,
771 };
772
773 let big_a = match ExtPoint::decompress(&pk.0) {
774 Some(p) => p,
775 None => return false,
776 };
777
778 let s_bytes: [u8; 32] = match sig.0[32..].try_into() {
779 Ok(b) => b,
780 Err(_) => return false,
781 };
782
783 {
785 let mut sl = [0u64; 4];
786 for i in 0..4 {
787 sl[i] = u64::from_le_bytes(s_bytes[i * 8..(i + 1) * 8].try_into().unwrap());
788 }
789 let (_, borrow) = sl[0].overflowing_sub(L[0]);
790 let (_, borrow) = sbb(sl[1], L[1], borrow);
791 let (_, borrow) = sbb(sl[2], L[2], borrow);
792 let (_, borrow) = sbb(sl[3], L[3], borrow);
793 if !borrow {
794 return false; }
796 }
797
798 let mut hasher = Sha512::new();
800 update_dom2(&mut hasher, dom2);
801 hasher.update(&r_bytes);
802 hasher.update(&pk.0);
803 hasher.update(message_or_hash);
804 let k_hash = hasher.finalize();
805 let mut k_wide = [0u8; 64];
806 k_wide.copy_from_slice(&k_hash);
807 let k = sc_reduce(&k_wide);
808
809 let sb = ExtPoint::basepoint().scalar_mul(&s_bytes);
811 let ka = big_a.scalar_mul(&k);
812 let rhs = big_r.add(ka);
813
814 let lhs = sb.double().double().double();
816 let rhs = rhs.double().double().double();
817
818 lhs.equals(rhs)
819}
820
821const DOM2_LITERAL: &[u8] = b"SigEd25519 no Ed25519 collisions";
832
833fn build_dom2(f: u8, context: &[u8]) -> Option<Vec<u8>> {
837 if context.len() > 255 {
838 return None;
839 }
840 let mut out = Vec::with_capacity(DOM2_LITERAL.len() + 2 + context.len());
841 out.extend_from_slice(DOM2_LITERAL);
842 out.push(f);
843 out.push(context.len() as u8);
844 out.extend_from_slice(context);
845 Some(out)
846}
847
848pub fn ed25519_sign(sk: &Ed25519SecretKey, msg: &[u8]) -> Ed25519Signature {
859 ed25519_sign_internal(sk, msg, None)
860}
861
862pub fn ed25519_verify(pk: &Ed25519PublicKey, msg: &[u8], sig: &Ed25519Signature) -> bool {
864 ed25519_verify_internal(pk, msg, sig, None)
865}
866
867pub fn ed25519ctx_sign(sk: &Ed25519SecretKey, msg: &[u8], context: &[u8]) -> Option<Ed25519Signature> {
885 if context.is_empty() {
886 return None;
887 }
888 let dom2 = build_dom2(0, context)?;
889 Some(ed25519_sign_internal(sk, msg, Some(&dom2)))
890}
891
892pub fn ed25519ctx_verify(pk: &Ed25519PublicKey, msg: &[u8], context: &[u8], sig: &Ed25519Signature) -> bool {
899 if context.is_empty() || context.len() > 255 {
900 return false;
901 }
902 let dom2 = match build_dom2(0, context) {
903 Some(d) => d,
904 None => return false,
905 };
906 ed25519_verify_internal(pk, msg, sig, Some(&dom2))
907}
908
909pub fn ed25519ph_sign(sk: &Ed25519SecretKey, msg: &[u8], context: &[u8]) -> Option<Ed25519Signature> {
928 let dom2 = build_dom2(1, context)?;
929 let m_prime = Sha512::hash(msg);
930 Some(ed25519_sign_internal(sk, &m_prime, Some(&dom2)))
931}
932
933pub fn ed25519ph_verify(pk: &Ed25519PublicKey, msg: &[u8], context: &[u8], sig: &Ed25519Signature) -> bool {
935 if context.len() > 255 {
936 return false;
937 }
938 let dom2 = match build_dom2(1, context) {
939 Some(d) => d,
940 None => return false,
941 };
942 let m_prime = Sha512::hash(msg);
943 ed25519_verify_internal(pk, &m_prime, sig, Some(&dom2))
944}
945
946pub fn ed25519ph_sign_prehashed(sk: &Ed25519SecretKey, prehashed: &[u8], context: &[u8]) -> Option<Ed25519Signature> {
954 if prehashed.len() != 64 {
955 return None;
956 }
957 let dom2 = build_dom2(1, context)?;
958 Some(ed25519_sign_internal(sk, prehashed, Some(&dom2)))
959}
960
961pub fn ed25519ph_verify_prehashed(
964 pk: &Ed25519PublicKey,
965 prehashed: &[u8],
966 context: &[u8],
967 sig: &Ed25519Signature,
968) -> bool {
969 if prehashed.len() != 64 || context.len() > 255 {
970 return false;
971 }
972 let dom2 = match build_dom2(1, context) {
973 Some(d) => d,
974 None => return false,
975 };
976 ed25519_verify_internal(pk, prehashed, sig, Some(&dom2))
977}
978
979#[cfg(test)]
996mod tests {
997 use super::*;
998
999 fn hex_to_bytes(s: &str) -> Vec<u8> {
1000 (0..s.len())
1001 .step_by(2)
1002 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
1003 .collect()
1004 }
1005
1006 #[test]
1007 fn test_fe25519_basic() {
1008 let a = Fe25519::ONE;
1009 let b = Fe25519::ONE;
1010 let c = a.add(b);
1011 assert_eq!(c.0[0], 2);
1012 assert_eq!(c.0[1], 0);
1013
1014 let d = c.sub(a);
1015 assert!(d.equals(Fe25519::ONE));
1016 }
1017
1018 #[test]
1019 fn test_fe25519_mul() {
1020 let a = Fe25519::from_u64(7);
1021 let b = Fe25519::from_u64(13);
1022 let c = a.mul(b);
1023 assert!(c.equals(Fe25519::from_u64(91)));
1024 }
1025
1026 #[test]
1027 fn test_fe25519_inv() {
1028 let a = Fe25519::from_u64(42);
1029 let b = a.inv();
1030 let c = a.mul(b);
1031 assert!(c.equals(Fe25519::ONE));
1032 }
1033
1034 #[test]
1035 fn test_basepoint_on_curve() {
1036 let x2 = B_X.square();
1038 let y2 = B_Y.square();
1039 let lhs = y2.sub(x2);
1040 let rhs = Fe25519::ONE.add(D.mul(x2).mul(y2));
1041 assert!(lhs.equals(rhs), "Base point not on curve!");
1042 }
1043
1044 #[test]
1045 fn test_d_constant() {
1046 let n = Fe25519::from_u64(121665).neg();
1048 let d_inv = Fe25519::from_u64(121666).inv();
1049 let d_computed = n.mul(d_inv);
1050 assert!(d_computed.equals(D), "D constant is wrong");
1051 }
1052
1053 #[test]
1054 fn test_d2_constant() {
1055 let d2_computed = D.add(D);
1056 assert!(d2_computed.equals(D2), "D2 constant is wrong");
1057 }
1058
1059 #[test]
1060 fn test_basepoint_compress_decompress() {
1061 let bp = ExtPoint::basepoint();
1062 let compressed = bp.compress();
1063 let decompressed = ExtPoint::decompress(&compressed).expect("decompress failed");
1064 assert!(bp.equals(decompressed));
1065 }
1066
1067 fn naive_scalar_mul(p: ExtPoint, scalar: &[u8; 32]) -> ExtPoint {
1068 let mut acc = ExtPoint::IDENTITY;
1071 let mut started = false;
1072 for byte_idx in (0..32).rev() {
1073 for bit_idx in (0..8).rev() {
1074 if started {
1075 acc = acc.double();
1076 }
1077 let bit = (scalar[byte_idx] >> bit_idx) & 1;
1078 if bit == 1 {
1079 if !started {
1080 acc = p;
1081 started = true;
1082 } else {
1083 acc = acc.add(p);
1084 }
1085 }
1086 }
1087 }
1088 acc
1089 }
1090
1091 #[test]
1092 fn test_scalar_mul_vs_naive() {
1093 let bp = ExtPoint::basepoint();
1094 let mut s = [0u8; 32];
1095 for i in 0..32 {
1097 s[i] = (i as u8) ^ 0xa5;
1098 }
1099 s[31] &= 0x7f;
1100 let r1 = bp.scalar_mul(&s);
1101 let r2 = naive_scalar_mul(bp, &s);
1102 assert!(r1.equals(r2));
1103 }
1104
1105 #[test]
1106 fn test_sc_reduce_basic() {
1107 let mut x = [0u8; 64];
1109 x[0] = 1;
1110 let r = sc_reduce(&x);
1111 assert_eq!(r[0], 1);
1112 for i in 1..32 {
1113 assert_eq!(r[i], 0);
1114 }
1115
1116 let mut x = [0u8; 64];
1118 x[0..8].copy_from_slice(&L[0].to_le_bytes());
1119 x[8..16].copy_from_slice(&L[1].to_le_bytes());
1120 x[16..24].copy_from_slice(&L[2].to_le_bytes());
1121 x[24..32].copy_from_slice(&L[3].to_le_bytes());
1122 let r = sc_reduce(&x);
1123 for i in 0..32 {
1124 assert_eq!(r[i], 0, "L mod L should be 0, byte {}", i);
1125 }
1126
1127 let mut x = [0u8; 64];
1129 x[0..8].copy_from_slice(&(L[0] + 1).to_le_bytes());
1130 x[8..16].copy_from_slice(&L[1].to_le_bytes());
1131 x[16..24].copy_from_slice(&L[2].to_le_bytes());
1132 x[24..32].copy_from_slice(&L[3].to_le_bytes());
1133 let r = sc_reduce(&x);
1134 assert_eq!(r[0], 1);
1135 }
1136
1137 #[test]
1138 fn test_fe_pow_fermat() {
1139 let a = Fe25519::from_u64(7);
1141 let pm1: [u64; 4] = [
1142 0xFFFF_FFFF_FFFF_FFEC,
1143 0xFFFF_FFFF_FFFF_FFFF,
1144 0xFFFF_FFFF_FFFF_FFFF,
1145 0x7FFF_FFFF_FFFF_FFFF,
1146 ];
1147 let r = a.pow(pm1);
1148 assert!(r.equals(Fe25519::ONE));
1149 }
1150
1151 #[test]
1152 fn test_scalar_mul_two() {
1153 let bp = ExtPoint::basepoint();
1154 let mut two = [0u8; 32];
1155 two[0] = 2;
1156 let r = bp.scalar_mul(&two);
1157 assert!(r.equals(bp.double()));
1158 }
1159
1160 #[test]
1161 fn test_scalar_mul_three() {
1162 let bp = ExtPoint::basepoint();
1163 let mut three = [0u8; 32];
1164 three[0] = 3;
1165 let r = bp.scalar_mul(&three);
1166 assert!(r.equals(bp.double().add(bp)));
1167 }
1168
1169 #[test]
1170 fn test_scalar_mul_identity() {
1171 let bp = ExtPoint::basepoint();
1172 let mut one = [0u8; 32];
1173 one[0] = 1;
1174 let result = bp.scalar_mul(&one);
1175 assert!(result.equals(bp));
1176 }
1177
1178 #[test]
1179 fn test_point_add_double() {
1180 let bp = ExtPoint::basepoint();
1181 let bp2_add = bp.add(bp);
1182 let bp2_dbl = bp.double();
1183 assert!(bp2_add.equals(bp2_dbl));
1184 }
1185
1186 #[test]
1188 fn test_ed25519_vector1() {
1189 let sk_hex = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60";
1190 let pk_hex = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
1191 let sig_hex = "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155\
1192 5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b";
1193
1194 let sk_bytes = hex_to_bytes(sk_hex);
1195 let pk_bytes = hex_to_bytes(pk_hex);
1196 let sig_bytes = hex_to_bytes(sig_hex);
1197
1198 let mut sk = [0u8; 32];
1199 sk.copy_from_slice(&sk_bytes);
1200
1201 let (pk, secret) = ed25519_keygen(&sk);
1202 assert_eq!(&pk.0[..], &pk_bytes[..], "Public key mismatch");
1203
1204 let signature = ed25519_sign(&secret, b"");
1205 assert_eq!(&signature.0[..], &sig_bytes[..], "Signature mismatch");
1206
1207 assert!(ed25519_verify(&pk, b"", &signature), "Verification failed");
1208 }
1209
1210 #[test]
1212 fn test_ed25519_vector2() {
1213 let sk_hex = "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb";
1214 let pk_hex = "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c";
1215 let sig_hex = "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da\
1216 085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00";
1217
1218 let sk_bytes = hex_to_bytes(sk_hex);
1219 let pk_bytes = hex_to_bytes(pk_hex);
1220 let sig_bytes = hex_to_bytes(sig_hex);
1221
1222 let mut sk = [0u8; 32];
1223 sk.copy_from_slice(&sk_bytes);
1224
1225 let (pk, secret) = ed25519_keygen(&sk);
1226 assert_eq!(&pk.0[..], &pk_bytes[..], "Public key mismatch");
1227
1228 let msg = [0x72u8];
1229 let signature = ed25519_sign(&secret, &msg);
1230 assert_eq!(&signature.0[..], &sig_bytes[..], "Signature mismatch");
1231
1232 assert!(ed25519_verify(&pk, &msg, &signature), "Verification failed");
1233 }
1234
1235 #[test]
1244 fn rfc8032_section_7_2_ed25519ctx_vector() {
1245 let sk_bytes = hex_to_bytes("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6");
1246 let pk_bytes = hex_to_bytes("dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292");
1247 let msg = hex_to_bytes("f726936d19c800494e3fdaff20b276a8");
1248 let context = hex_to_bytes("666f6f"); let sig_bytes = hex_to_bytes(
1250 "55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a\
1251 8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d",
1252 );
1253
1254 let mut sk_arr = [0u8; 32];
1255 sk_arr.copy_from_slice(&sk_bytes);
1256 let (pk, secret) = ed25519_keygen(&sk_arr);
1257 assert_eq!(pk.0.as_slice(), pk_bytes.as_slice(), "pk mismatch");
1258
1259 let signature = ed25519ctx_sign(&secret, &msg, &context).expect("ctx_sign");
1261 assert_eq!(
1262 signature.0.as_slice(),
1263 sig_bytes.as_slice(),
1264 "Ed25519ctx signature mismatch"
1265 );
1266
1267 assert!(ed25519ctx_verify(&pk, &msg, &context, &signature));
1269 }
1270
1271 #[test]
1280 fn rfc8032_section_7_3_ed25519ph_vector() {
1281 let sk_bytes = hex_to_bytes("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42");
1282 let pk_bytes = hex_to_bytes("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf");
1283 let msg = hex_to_bytes("616263"); let sig_bytes = hex_to_bytes(
1285 "98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae41\
1286 31f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406",
1287 );
1288
1289 let mut sk_arr = [0u8; 32];
1290 sk_arr.copy_from_slice(&sk_bytes);
1291 let (pk, secret) = ed25519_keygen(&sk_arr);
1292 assert_eq!(pk.0.as_slice(), pk_bytes.as_slice(), "pk mismatch");
1293
1294 let signature = ed25519ph_sign(&secret, &msg, b"").expect("ph_sign");
1296 assert_eq!(
1297 signature.0.as_slice(),
1298 sig_bytes.as_slice(),
1299 "Ed25519ph signature mismatch"
1300 );
1301
1302 assert!(ed25519ph_verify(&pk, &msg, b"", &signature));
1303 }
1304
1305 #[test]
1309 fn ed25519ph_prehashed_matches_message_form() {
1310 let sk_bytes = hex_to_bytes("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42");
1311 let mut sk_arr = [0u8; 32];
1312 sk_arr.copy_from_slice(&sk_bytes);
1313 let (pk, secret) = ed25519_keygen(&sk_arr);
1314
1315 let from_msg = ed25519ph_sign(&secret, b"abc", b"").expect("ph_sign");
1316
1317 let digest = Sha512::hash(b"abc");
1319 let from_digest = ed25519ph_sign_prehashed(&secret, &digest, b"").expect("ph_sign_prehashed");
1320
1321 assert_eq!(from_msg.0, from_digest.0);
1322
1323 assert!(ed25519ph_verify(&pk, b"abc", b"", &from_msg));
1325 assert!(ed25519ph_verify_prehashed(&pk, &digest, b"", &from_msg));
1326 }
1327
1328 fn make_test_keys() -> (Ed25519PublicKey, Ed25519SecretKey) {
1338 let sk_bytes = hex_to_bytes("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6");
1339 let mut sk = [0u8; 32];
1340 sk.copy_from_slice(&sk_bytes);
1341 ed25519_keygen(&sk)
1342 }
1343
1344 #[test]
1345 fn ed25519ctx_requires_nonempty_context() {
1346 let (_pk, sk) = make_test_keys();
1347 assert!(ed25519ctx_sign(&sk, b"any message", b"").is_none());
1349 }
1350
1351 #[test]
1352 fn ed25519ctx_signature_does_not_verify_as_pure() {
1353 let (pk, sk) = make_test_keys();
1354 let msg = b"shared message";
1355 let sig = ed25519ctx_sign(&sk, msg, b"appA").expect("ctx_sign");
1356 assert!(!ed25519_verify(&pk, msg, &sig));
1359 }
1360
1361 #[test]
1362 fn pure_signature_does_not_verify_as_ctx() {
1363 let (pk, sk) = make_test_keys();
1364 let msg = b"shared message";
1365 let sig = ed25519_sign(&sk, msg);
1366 assert!(!ed25519ctx_verify(&pk, msg, b"appA", &sig));
1369 }
1370
1371 #[test]
1372 fn ed25519ctx_different_contexts_dont_cross() {
1373 let (pk, sk) = make_test_keys();
1374 let msg = b"shared message";
1375 let sig_a = ed25519ctx_sign(&sk, msg, b"appA").expect("ctx_sign A");
1376 let sig_b = ed25519ctx_sign(&sk, msg, b"appB").expect("ctx_sign B");
1377
1378 assert!(ed25519ctx_verify(&pk, msg, b"appA", &sig_a));
1380 assert!(ed25519ctx_verify(&pk, msg, b"appB", &sig_b));
1381
1382 assert!(!ed25519ctx_verify(&pk, msg, b"appB", &sig_a));
1384 assert!(!ed25519ctx_verify(&pk, msg, b"appA", &sig_b));
1385
1386 assert_ne!(sig_a.0, sig_b.0);
1389 }
1390
1391 #[test]
1392 fn ed25519ph_signature_does_not_verify_as_pure() {
1393 let (pk, sk) = make_test_keys();
1394 let msg = b"shared message";
1395 let sig = ed25519ph_sign(&sk, msg, b"").expect("ph_sign");
1396 assert!(!ed25519_verify(&pk, msg, &sig));
1399 }
1400
1401 #[test]
1402 fn ed25519ph_signature_does_not_verify_as_ctx() {
1403 let (pk, sk) = make_test_keys();
1404 let msg = b"shared message";
1405 let sig = ed25519ph_sign(&sk, msg, b"context").expect("ph_sign");
1406 assert!(!ed25519ctx_verify(&pk, msg, b"context", &sig));
1409 }
1410
1411 #[test]
1412 fn ed25519ctx_max_context_length() {
1413 let (pk, sk) = make_test_keys();
1414 let msg = b"x";
1415 let ctx_max = vec![0xa5u8; 255];
1417 let sig = ed25519ctx_sign(&sk, msg, &ctx_max).expect("ctx max len");
1418 assert!(ed25519ctx_verify(&pk, msg, &ctx_max, &sig));
1419
1420 let ctx_too_long = vec![0xa5u8; 256];
1423 assert!(ed25519ctx_sign(&sk, msg, &ctx_too_long).is_none());
1424 assert!(!ed25519ctx_verify(&pk, msg, &ctx_too_long, &sig));
1425 }
1426}