module Noble::Ed25519

Extended Modules

Defined in:

noble-ed25519.cr

Constant Summary

BigInt256 = BigInt.new(255)
CURVE_ORDER = (Two ** (BigInt.new(252))) + (BigInt.new("27742317777372353535851937790883648493"))
D_MINUS_ONE_SQ = BigInt.new("40440834346308536858101042469323190826248399146238708352240133220865137265952")

(d-1)²

Hexes = (0..255).each.with_index.map do |v, i| (i.to_s(16)).rjust(2, '0') end.to_a

Convert between types

INVSQRT_A_MINUS_D = BigInt.new("54469307008909316920995813868745141605393597292927456921205312896311721017578")

1 / √(a-d)

MAX_256B = Noble::Ed25519::Two ** (BigInt.new(256))
One = BigInt.new(1)
ONE_MINUS_D_SQ = BigInt.new("1159843021668779879193775521855586647937357759715417654439879720876111806838")

1-d²

PointPrecomputes = Hash(Point, Array(ExtendedPoint)).new()

Stores precomputed values for points.

SQRT_AD_MINUS_ONE = BigInt.new("25063068953384623474111414158702152701244531502492656460079210482610430750235")

√(ad - 1)

SQRT_D = BigInt.new("6853475219497561581579357271197624642482790079785650197046958215289687604742")

√d aka sqrt(-486664)

SQRT_M1 = BigInt.new("19681161376707505956807079304988542015446066515923890162744021073123829784752")

√(-1) aka √(a) aka 2^((p-1)/4)

Two = BigInt.new(2)
Zero = BigInt.new(0)

Class Method Summary

Instance Method Summary

Class Method Detail

def self.normalizeScalar(num : Int, max : BigInt, strict = true) : BigInt #

** Checks for num to be in range: For strict == true: 0 < num < max. For strict == false: 0 <= num < max. Converts non-float safe numbers to BigInts. /


[View source]

Instance Method Detail

def adjustBytes25519(bytes : Bytes) : Bytes #

[View source]
def bytes255ToNumberLE(bytes : Bytes) : BigInt #

[View source]
def bytesToHex(uint8a : Bytes) : String #

[View source]
def bytesToNumberLE(uint8a : Bytes) : BigInt #

Little Endian


[View source]
def concatBytes(*arrays) : Bytes #

[View source]
def cswap(swap : BigInt, x_2 : BigInt, x_3 : BigInt) : Tuple(BigInt, BigInt) #

cswap from RFC7748


[View source]
def decodeScalar25519(n : Hex) : BigInt #

[View source]
def decodeUCoordinate(uEnc : Hex) : BigInt #

[View source]
def edIsNegative(num : BigInt) #

Little-endian check for first LE bit (last BE bit)


[View source]
def encodeUCoordinate(u : BigInt) : Bytes #

[View source]
def ensureBytes(hex : Hex, expectedLength : Int32 | Nil = nil) : Bytes #

[View source]
def equalBytes(b1 : Bytes, b2 : Bytes) #

[View source]
def getExtendedPublicKey(key : PrivKey) #

Private convenience method RFC8032 5.1.5


[View source]
def getPublicKey(privateKey : PrivKey) : Bytes #

** Calculates ed25519 public key.

  1. private key is hashed with sha512, then first 32 bytes are taken from the hash
  2. 3 least significant bits of the first byte are cleared RFC8032 5.1.5 /

[View source]
def getSharedSecret(privateKey : PrivKey, publicKey : Hex) : Bytes #

** Calculates X25519 DH shared secret from ed25519 private & public keys. Curve25519 used in X25519 consumes private keys as-is, while ed25519 hashes them with sha512. Which means we will need to normalize ed25519 seeds to "hashed repr". @param privateKey ed25519 private key @param publicKey ed25519 public key @returns X25519 shared key /


[View source]
def hexToBytes(hex : String) : Bytes #

Caching slows it down 2-3x


[View source]
def invert(number : BigInt, modulo : BigInt = Curve::P) : BigInt #

Note: this egcd-based invert is 50% faster than powMod-based one. Inverses number over modulo


[View source]
def invertBatch(nums : Array(BigInt), p : BigInt = Curve::P) : Array(BigInt) #

** Takes a list of numbers, efficiently inverts all of them. @param nums list of BigInts @param p modulo @returns list of inverted BigInts @example Noble::Ed25519.invertBatch([1n, 2n, 4n], 21n)

=> [1n, 11n, 16n]

/


[View source]
def invertSqrt(number : BigInt) #

Calculates 1/√(number)


[View source]
def mod(a : BigInt, b : BigInt = Curve::P) : BigInt #

[View source]
def montgomeryLadder(pointU : BigInt, scalar : BigInt) : BigInt #

x25519 from 4 **

@param pointU u coordinate (x) on Montgomery Curve 25519 @param scalar by which the point would be multiplied @returns new Point on Montgomery curve /


[View source]
def numberTo32BytesBE(num : BigInt) : Bytes #

[View source]
def numberTo32BytesLE(num : BigInt) : Bytes #

[View source]
def pow2(x : BigInt, power : BigInt) : BigInt #

Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)


[View source]
def pow_2_252_3(x : BigInt) #

Power to (p-5)/8 aka x^(2^252-3) Used to calculate y - the square root of y². Exponentiates it to very big number. We are unwrapping the loop because it's 2x faster. (2n**252n-3n).toString(2) would produce bits [250x 1, 0, 1] We are multiplying it bit-by-bit


[View source]
def sha512ModqLE(*args) : BigInt #

Little-endian SHA512 with modulo n


[View source]
def sign(message : Hex, privateKey : Hex) : Bytes #

** Signs message with privateKey. RFC8032 5.1.6 /


[View source]
def uvRatio(u : BigInt, v : BigInt) : NamedTuple(isValid: Bool, value: BigInt) #

Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3. Constant-time prettier-ignore


[View source]
def verify(sig : SigType, message : Hex, publicKey : PubKey) : Bool #

** Verifies ed25519 signature against message and public key. An extended group equation is checked. RFC8032 5.1.7 Compliant with ZIP215: 0 <= sig.R/publicKey < 2**256 (can be >= curve.P) 0 <= sig.s < l Not compliant with RFC8032: it's not possible to comply to both ZIP & RFC at the same time. /


[View source]