Skip to content

Commit c45300f

Browse files
thebenternCopilot
andauthored
Apply suggestion from @Copilot
Co-authored-by: Copilot <[email protected]>
1 parent ef4220f commit c45300f

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

Meshtastic/Crypto/XEdDSASigning.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,39 @@ public static byte[] ConvertX25519PublicKeyToEd25519(byte[] x25519PublicKey)
7979

8080
// Clear the sign bit (bit 7 of the last byte) as per Ed25519 specification
8181
edPublicKey[31] &= 0x7F;
82-
82+
// Implements the birational map from Montgomery (X25519) u to Edwards (Ed25519) y:
83+
// y = (u - 1) / (u + 1) mod p
84+
// See: https://tools.ietf.org/html/rfc7748#section-5
85+
86+
// Curve25519 prime: 2^255 - 19
87+
BigInteger p = Ed25519FieldElement.Q;
88+
89+
// Interpret the X25519 public key as a little-endian integer u
90+
byte[] uBytes = new byte[32];
91+
Array.Copy(x25519PublicKey, uBytes, 32);
92+
// Ensure top bit is masked (Montgomery u-coordinate is 255 bits)
93+
uBytes[31] &= 0x7F;
94+
BigInteger u = new BigInteger(1, uBytes.Reverse().ToArray());
95+
96+
// Compute y = (u - 1) * (u + 1)^-1 mod p
97+
BigInteger one = BigInteger.One;
98+
BigInteger uMinus1 = u.Subtract(one).Mod(p);
99+
BigInteger uPlus1 = u.Add(one).Mod(p);
100+
BigInteger uPlus1Inv = uPlus1.ModInverse(p);
101+
BigInteger y = uMinus1.Multiply(uPlus1Inv).Mod(p);
102+
103+
// Encode y as 32-byte little-endian
104+
byte[] yBytes = y.ToByteArrayUnsigned();
105+
byte[] edPublicKey = new byte[32];
106+
// Copy yBytes into edPublicKey (little-endian)
107+
for (int i = 0; i < yBytes.Length && i < 32; i++)
108+
{
109+
edPublicKey[i] = yBytes[yBytes.Length - 1 - i];
110+
}
111+
// If yBytes is shorter than 32 bytes, the rest is already zero
112+
113+
// Set the sign bit to 0 (positive x)
114+
edPublicKey[31] &= 0x7F;
83115
return edPublicKey;
84116
}
85117

0 commit comments

Comments
 (0)