加密算法:深度解析Ed25519原理

简介: 在 Solana 开发过程中,我一直对 Ed25519 加密算法 如何生成公钥、签名以及验证签名的机制感到困惑。为了弄清这一点,我查阅了大量相关资料,终于对其流程有了更清晰的理解。在此记录实现过程,方便日后查阅。


目录

一、编写目的

二、算法流程图

三、步骤分析

1.公钥生成

2.消息签名

3.签名验证

这里签名为什么可以被验证?

四、源代码


Welcome to Code Block's blog

本篇文章主要介绍了

[加密算法:深度解析Ed25519加密]

❤博主广交技术好友,喜欢文章的可以关注一下❤

一、编写目的

       在 Solana 开发过程中,我一直对 Ed25519 加密算法 如何生成公钥、签名以及验证签名的机制感到困惑。为了弄清这一点,我查阅了大量相关资料,终于对其流程有了更清晰的理解。在此记录实现过程,方便日后查阅。

二、算法流程图

image.gif 编辑

通过官网上的算法流程图可以看到,其中有几个部分是彩色的,其解释如下:

  • seed(k):随机的32bytes的值.该值为加密核心值,也是组成私钥的左半部分.
  • pubkey(A):公钥.作为用户的地址,在ed25519加密算法中作为私钥右半部分.
  • msg(M):需要被签名的消息.
  • R:组成签名的左半部分,为签名随机值.
  • S:组成签名的右半部分,为签名验证数据.

三、步骤分析

1.公钥生成

def publickey(sk):
    """
    生成给定私钥的公钥。
    参数:
    sk (bytes): 私钥,字节序列。
    返回:
    bytes: 公钥,字节序列。
    该函数首先计算私钥的哈希值,然后根据哈希值生成一个标量 a。
    使用标量 a 和基点 B 进行标量乘法运算,得到点 A。
    最后将点 A 编码为字节序列并返回。
    注意:
    - 函数依赖于外部定义的 H、bit、scalarmult、B 和 encodepoint 函数或变量。
    - b 是一个全局变量,表示位数。
    """
    h = H(sk)
    a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
    print(a)
    A = scalarmult(B, a)
    print(A)
    return encodepoint(A)

image.gif

  • Sha512

       当随机seek值(32 bytes)生成后,将seek值通过Hash算法sha512转换其为hash值(64 bytes).

  • sk派生a

       通过下述派生公式,生成一个派生的随机值:

                                       

       这里说是随机值,但因为是规定的派生方法,所以seek值不变的情况下,a的值也不会发生改变.

这也是为什么私钥不变生成的公钥不变.

  • 计算曲线点(scalarmult(B, a))

      通过固定的基点B,将a作为标量值,进行累加的标量乘法运算,其得出的值为椭圆曲线上的一个点.即solana公钥为椭圆曲线上的点.

  • 编码为公钥(encodepoint(A))

       将生成的椭圆上的点,通过遍历的方式将其转换为32 bytes的值,该值作为公钥,同时也是私钥的右半部分.

测试:

import os
from ed255191 import publickey
import base58
seed = os.urandom(32)
# 计算 Ed25519 公钥
pk = publickey(seed)
# Solana 私钥 = 种子(32 字节) + 公钥(32 字节)
solana_secret_key = seed + pk
# 以base58打印密钥
print("Public Key 32 bytes:", base58.b58encode(pk))
print("Solana Private Key 64 bytes:", base58.b58encode(solana_secret_key))

image.gif

输出:

Public Key 32 bytes: b'8Y4MaxUyeTrXFsDGtAAoqHvuZNKNGgd43KaYtyQ29wdq'
Solana Private Key 64 bytes: b'53eadFesuqNF1PMW4cd6PTrrmYaPJAUc19upagtRQfiYLQfTRDKSgbBFcShEHM9qghrmo1SuKFoJbzeqLaGNyczT'

image.gif

输出上述内容,可以直接在solana作为公私钥地址使用.

2.消息签名

def signature(m, sk, pk):
    """
    生成Ed25519签名。
    参数:
    m (bytes): 要签名的消息。
    sk (bytes): 私钥。
    pk (bytes): 公钥。
    返回:
    bytes: 签名,由 R 和 S 组成。
    过程:
    1. 计算私钥哈希 h。
    2. 从 h 中提取部分位生成私钥 a。
    3. 使用 h 的一部分和消息 m 生成随机数 r。
    4. 计算随机点 R = r * B。
    5. 计算哈希值 c = Hint(encodepoint(R) + pk + m)。
    6. 计算签名 S = (r + c * a) % l。
    7. 返回签名 encodepoint(R) + encodeint(S)。
    注意:
    - r 对于每条不同的消息 m 都是不同的,确保签名的唯一性。
    - S 包含了随机数 r 和私钥 a 的隐藏计算,保证签名的安全性。
    """
    h = H(sk)
    a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
    #取 h 的部分(h[b // 8 : b // 4])作为一个随机种子 结合m 生成hash值
    #这样 r 对于每条不同的 m 都是不同的,确保签名的唯一性。
    r = Hint(h[b // 8 : b // 4] + m)
    #随机值生成随机点
    R = scalarmult(B, r)
    #计算 c = Hint(encodepoint(R) + pk + m),即对 R、公钥 pk 和消息 m 进行哈希。
    #计算 S = (r + c * a) % l,这里:
    #       c * a 相当于用私钥 a 进行了一次隐藏的计算。
    #       r 作为随机数,确保 S 是不可预测的。
    #       mod l 使得 S 处于有限域 l 内,保证安全性。
    S = (r + Hint(encodepoint(R) + pk + m) * a) % l
    return encodepoint(R) + encodeint(S)

image.gif

  • sha512和派生a

       这里使用与公钥生成时同样的算法对h和a进行计算.

  • 生成随机值R

       通过h(seek的32位bytes)后32为与r进行相加,通过Hint方法计算哈希值的位的加权和。再通过标量乘法计算R.(32 bytes) 然后根据Schnorr 签名公式(该公式保证了该签名可被验证):

                                                mod l

       计算出S.R和S共同组成了签名消息.

R 对于每条不同的消息 m 都是不同的,确保签名的唯一性。
S 包含了随机数 r 和私钥 a 的隐藏计算,保证签名的安全性。

测试:

sign=signature(b"123",seed,pk)
print("signature the 123:",base58.b58encode(sign))

image.gif

输出:

R: [6324733128348069932552712847458797216869310762106586087538471940014706165507, 28062308455787357155134324845859090190481803788753592421647963767216412318834]
S: 5332744685477174614042576231653933898918923940183121946240407635890135823280
signature the 123: b'3HcZN9B8WExQdTqiFPEZUGndqVgtrJhwNoCwMm7wHCq2K5wxrWpdJXgMFBgkimA4r1nKqCpekurwstkimY6au9Dc'

image.gif

3.签名验证

def checkvalid(s, m, pk) -> bool:
    """
    验证给定的签名是否有效。
    参数:
    s (bytes): 签名,长度应为 b // 4。
    m (bytes): 消息。
    pk (bytes): 公钥,长度应为 b // 8。
    返回:
    bool: 如果签名有效,返回 True;否则抛出异常。
    异常:
    Exception: 当签名长度或公钥长度不正确时抛出。
    Exception: 当签名验证失败时抛出。
    """
    if len(s) != b // 4:
        raise Exception("Signature length is wrong")
    if len(pk) != b // 8:
        raise Exception("Public-key length is wrong")
    #----------------签名的前半部分和后半部分--------------------------
    R = decodepoint(s[: b // 8])  # s取前32位 (反向计算随机点)
    S = decodeint(s[b // 8 : b // 4]) # s取32到64位
    #-----------------公钥和挑战值-----------------------------------
    A = decodepoint(pk)           # pk为32位 (计算公钥点)
    c = Hint(encodepoint(R) + pk + m) # 计算挑战值
    #-----------------验证签名---------------------------------------
    #计算 c = Hint(encodepoint(R) + pk + m),即对 R、公钥 pk 和消息 m 进行哈希。
    #计算 S = (r + c * a) % l,这里:
    #       c * a 相当于用私钥 a 进行了一次隐藏的计算。
    #       r 作为随机数,确保 S 是不可预测的。
    #       mod l 使得 S 处于有限域 l 内,保证安全性。
    #       S⋅B=R+c⋅A
    #       S=(r + Hint(encodepoint(R) + pk + m) * a) % l
    #       A=B*a
    #       S*B=B*r+c.B*a=B*(r+c*a)
    #       B*S=B*(r+c*a)
    #       B*r+B*a*c=B*(r+c*a)
    if scalarmult(B, S) != edwards(R, scalarmult(A, c)):
        raise Exception("Signature does not pass verification")
    return True

image.gif

  • 分割出R和S

       因为签名时使用(R,S)组合进行签名,所有这边直接对字节进行操作,取签名s的前32 bytes即为R,后32位即为S.

  • 计算A
    在以知公钥的情况下计算A,使用decodepoint将其转换为在椭圆上的点.
  • 计算h
    这是签名里计算S时的一部分,该部分在验证签名值是已知的(因为A,pk,m都是已知参数).

然后使用下述公式对其进行对比验证:

测试:

valid=checkvalid(sign,b"123",pk)
print("valid:",valid)

image.gif

输出:

valid: True

image.gif

这里签名为什么可以被验证?

这里的签名为什么可以被验证,这里可以对公式进行做步骤推导:

在签名时R的计算公式为可以表示为:

在公钥生成时A的计算公式可以表示为:

将其带入公式后,原公式可表示为:

右边公式将提出后即可表示为:

这里即可得出在签名时使用的S为:

那S计算时还有个mod l为什么这里没有?

       因为椭圆曲线上的点加法是基于有限域运算的,即使不显式地写 mod l,计算仍然在这个有限集合内进行.

四、源代码

import hashlib
b = 256  # 位数
q = 2**255 - 19  # 素数 q
l = 2**252 + 27742317777372353535851937790883648493  # 素数 l
# 哈希函数,使用 SHA-512
def H(m):
    """
    计算给定消息的SHA-512哈希值。
    参数:
    m (bytes): 要进行哈希计算的消息。
    返回:
    bytes: 消息的SHA-512哈希值。
    """
    return hashlib.sha512(m).digest()
# 模幂运算,计算 (b^e) % m
def expmod(b, e, m):
    """
    计算 (b^e) % m 的值,使用递归的快速幂算法。
    参数:
    b (int): 底数
    e (int): 指数
    m (int): 模数
    返回:
    int: (b^e) % m 的结果
    示例:
    >>> expmod(2, 10, 1000)
    24
    如果 e == 0,返回 1。
    否则,递归地计算 expmod(b, e // 2, m) 的平方并取模 m。
    如果 e 是奇数,再乘以 b 并取模 m。
    """
    if e == 0:
        return 1
    t = expmod(b, e // 2, m) ** 2 % m  # 使用 `//` 确保 `e` 是整数
    if e & 1:
        t = (t * b) % m
    return t
# 计算 x 的逆元,满足 (x * inv(x)) % q == 1
def inv(x):
    """
    计算给定数值 x 在模 q 下的乘法逆元。
    这是通过使用费马小定理实现的,该定理指出,对于一个素数 q 和一个整数 x,
    x^(q-1) ≡ 1 (mod q)。因此,x^(q-2) ≡ x^(-1) (mod q)。
    参数:
    x (int): 需要计算逆元的整数。
    返回:
    int: x 在模 q 下的乘法逆元。
    """
    return expmod(x, q - 2, q)
d = -121665 * inv(121666)  # 常数 d
I = expmod(2, (q - 1) // 4, q)  # 常数 I
# 根据 y 坐标恢复 x 坐标
def xrecover(y):
    """
    根据给定的 y 值恢复 x 坐标。
    该函数用于从给定的 y 坐标恢复 x 坐标,适用于椭圆曲线密码学中的 Ed25519 算法。
    参数:
    y (int): y 坐标值。
    返回:
    int: 恢复的 x 坐标值。
    注意:
    - 该函数假设存在全局变量 d 和 q,它们分别是 Ed25519 曲线的常数。
    - inv 函数用于计算模逆。
    - expmod 函数用于计算模幂。
    - I 是虚数单位的平方根。
    """
    xx = (y * y - 1) * inv(d * y * y + 1)
    x = expmod(xx, (q + 3) // 8, q)
    if (x * x - xx) % q != 0:
        x = (x * I) % q
    if x % 2 != 0:
        x = q - x
    return x
By = 4 * inv(5)  # 基点 B 的 y 坐标
Bx = xrecover(By)  # 基点 B 的 x 坐标
B = [Bx % q, By % q]  # 基点 B
# 爱德华兹曲线上的点加法
def edwards(P, Q):
    """
    计算爱德华曲线上的点加法。
    参数:
    P (tuple): 第一个点 (x1, y1)。
    Q (tuple): 第二个点 (x2, y2)。
    返回:
    list: 结果点 (x3, y3),其中 x3 和 y3 都是模 q 的结果。
    公式:
    注意:
    - inv 表示求逆运算。
    - d 是爱德华曲线的常数参数。
    - q 是模数。
    """
    x1, y1 = P
    x2, y2 = Q
    x3 = (x1 * y2 + x2 * y1) * inv(1 + d * x1 * x2 * y1 * y2)
    y3 = (y1 * y2 + x1 * x2) * inv(1 - d * x1 * x2 * y1 * y2)
    return [x3 % q, y3 % q]
# 标量乘法,计算 e * P
def scalarmult(P, e):
    """
    对给定的点 P 进行标量乘法运算,计算 e * P。
    参数:
    P (list): 椭圆曲线上的一个点,表示为 [x, y]。
    e (int): 标量值。
    返回:
    list: 结果点 Q,表示为 [x, y]。
    说明:
    该函数使用二进制方法进行标量乘法运算。初始化结果点 Q 为无穷远点 [0, 1]。
    在循环中,如果 e 的最低位为 1,则将当前点 P 累加到 Q 上。然后将 P 自加(倍点运算),
    并将 e 右移一位(除以 2)。循环结束后返回结果点 Q。
    """
    Q = [0, 1]  # 初始化为无穷远点
    while e > 0:
        if e & 1:
            Q = edwards(Q, P)  # 累加
        P = edwards(P, P)  # 自加(倍点运算)
        e //= 2
    return Q
# 将整数编码为字节
def encodeint(y):
    """
    将整数编码为字节序列。
    参数:
    y (int): 要编码的整数。
    返回:
    bytes: 编码后的字节序列。
    """
    bits = [(y >> i) & 1 for i in range(b)]
    return bytes([sum([bits[i * 8 + j] << j for j in range(8)]) for i in range(b//8)])
# 将点编码为字节
def encodepoint(P):
    """
    将给定的点P编码为字节序列。
    参数:
    P (tuple): 一个包含两个整数 (x, y) 的元组,表示点的坐标。
    返回:
    bytes: 编码后的字节序列。
    说明:
    该函数首先将y坐标的每一位提取出来,形成一个位列表,然后将x坐标的最低位添加到该列表的末尾。
    最后,将这些位打包成字节序列并返回。
    """
    x, y = P
    bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
    return bytes([sum([bits[i * 8 + j] << j for j in range(8)]) for i in range(b // 8)])
# 获取哈希值的第 i 位
def bit(h, i):
    """
    返回字节数组 `h` 中第 `i` 位的值(0 或 1)。
    参数:
    h (bytes): 字节数组。
    i (int): 要检查的位的索引。
    返回:
    int: 位的值(0 或 1)。
    """
    return (h[i // 8] >> (i % 8)) & 1  # 修正 `ord()`
# 生成公钥
def publickey(sk):
    """
    生成给定私钥的公钥。
    参数:
    sk (bytes): 私钥,字节序列。
    返回:
    bytes: 公钥,字节序列。
    该函数首先计算私钥的哈希值,然后根据哈希值生成一个标量 a。
    使用标量 a 和基点 B 进行标量乘法运算,得到点 A。
    最后将点 A 编码为字节序列并返回。
    注意:
    - 函数依赖于外部定义的 H、bit、scalarmult、B 和 encodepoint 函数或变量。
    - b 是一个全局变量,表示位数。
    """
    h = H(sk)
    a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
    print(a)
    A = scalarmult(B, a)
    print(A)
    return encodepoint(A)
# 计算消息的哈希值
def Hint(m):
    """
    计算消息 m 的哈希值,并返回哈希值的位的加权和。
    参数:
    m (str): 输入消息。
    返回:
    int: 哈希值的位的加权和。
    该函数首先计算消息 m 的哈希值 h,然后计算 h 的每个位的加权和。
    加权和的计算方式是将每个位乘以 2 的该位索引次方,然后求和。
    """
    h = H(m)
    return sum(2 ** i * bit(h, i) for i in range(2 * b))
# 生成签名
def signature(m, sk, pk):
    """
    生成Ed25519签名。
    参数:
    m (bytes): 要签名的消息。
    sk (bytes): 私钥。
    pk (bytes): 公钥。
    返回:
    bytes: 签名,由 R 和 S 组成。
    过程:
    1. 计算私钥哈希 h。
    2. 从 h 中提取部分位生成私钥 a。
    3. 使用 h 的一部分和消息 m 生成随机数 r。
    4. 计算随机点 R = r * B。
    5. 计算哈希值 c = Hint(encodepoint(R) + pk + m)。
    6. 计算签名 S = (r + c * a) % l。
    7. 返回签名 encodepoint(R) + encodeint(S)。
    注意:
    - r 对于每条不同的消息 m 都是不同的,确保签名的唯一性。
    - S 包含了随机数 r 和私钥 a 的隐藏计算,保证签名的安全性。
    """
    h = H(sk)
    a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
    #取 h 的部分(h[b // 8 : b // 4])作为一个随机种子 结合m 生成hash值
    #这样 r 对于每条不同的 m 都是不同的,确保签名的唯一性。
    r = Hint(h[b // 8 : b // 4] + m)
    #随机值生成随机点
    R = scalarmult(B, r)
    #计算 c = Hint(encodepoint(R) + pk + m),即对 R、公钥 pk 和消息 m 进行哈希。
    #计算 S = (r + c * a) % l,这里:
    #       c * a 相当于用私钥 a 进行了一次隐藏的计算。
    #       r 作为随机数,确保 S 是不可预测的。
    #       mod l 使得 S 处于有限域 l 内,保证安全性。
    S = (r + Hint(encodepoint(R) + pk + m) * a) % l
    print("R:",R)
    print("S:",S)
    return encodepoint(R) + encodeint(S)
# 检查点是否在曲线上
def isoncurve(P):
    """
    检查给定点 P 是否在曲线上。
    参数:
    P (tuple): 包含点的 x 和 y 坐标的元组。
    返回:
    bool: 如果点在曲线上则返回 True,否则返回 False。
    """
    x, y = P
    return (-x * x + y * y - 1 - d * x * x * y * y) % q == 0
# 将字节解码为整数
def decodeint(s):
    """
    解码整数
    该函数将字节串 `s` 解码为一个整数。它通过对每个字节的位进行加权求和来实现这一点。
    参数:
    s (bytes): 要解码的字节串
    返回:
    int: 解码后的整数
    """
    return sum(2**i * bit(s,i) for i in range(0,b))
# 将字节解码为点
def decodepoint(s):
    """
    解码给定的字节串以恢复椭圆曲线上的点。
    参数:
    s (bytes): 要解码的字节串。
    返回:
    list: 椭圆曲线上的点 [x, y]。
    异常:
    Exception: 如果解码的点不在曲线上,则抛出异常。
    """
    y = sum(2**i * bit(s,i) for i in range(0,b-1))
    x = xrecover(y)
    if x & 1 != bit(s,b-1): x = q-x
    P = [x,y]
    if not isoncurve(P): raise Exception("decoding point that is not on curve")
    return P
# 验证签名
def checkvalid(s, m, pk) -> bool:
    """
    验证给定的签名是否有效。
    参数:
    s (bytes): 签名,长度应为 b // 4。
    m (bytes): 消息。
    pk (bytes): 公钥,长度应为 b // 8。
    返回:
    bool: 如果签名有效,返回 True;否则抛出异常。
    异常:
    Exception: 当签名长度或公钥长度不正确时抛出。
    Exception: 当签名验证失败时抛出。
    """
    if len(s) != b // 4:
        raise Exception("Signature length is wrong")
    if len(pk) != b // 8:
        raise Exception("Public-key length is wrong")
    #----------------签名的前半部分和后半部分--------------------------
    R = decodepoint(s[: b // 8])  # s取前32位 (反向计算随机点)
    S = decodeint(s[b // 8 : b // 4]) # s取32到64位
    #-----------------公钥和挑战值-----------------------------------
    A = decodepoint(pk)           # pk为32位 (计算公钥点)
    h = Hint(encodepoint(R) + pk + m) # 计算挑战值
    #-----------------验证签名---------------------------------------
    #计算 c = Hint(encodepoint(R) + pk + m),即对 R、公钥 pk 和消息 m 进行哈希。
    #计算 S = (r + c * a) % l,这里:
    #       c * a 相当于用私钥 a 进行了一次隐藏的计算。
    #       r 作为随机数,确保 S 是不可预测的。
    #       mod l 使得 S 处于有限域 l 内,保证安全性。
    #       S⋅B=R+c⋅A
    #       S=(r + Hint(encodepoint(R) + pk + m) * a) % l
    #       A=B*a
    #       S*B=B*r+c.B*a=B*(r+c*a)
    #       B*S=B*(r+c*a)
    #       B*r+B*a*c=B*(r+c*a)
    if scalarmult(B, S) != edwards(R, scalarmult(A, h)):
        raise Exception("Signature does not pass verification")
    return True

image.gif

上面为ed25519源代码,想要测试的朋友可以自己进行动手测试.

区块链内容感兴趣可以查看我的专栏:小试牛刀-区块链

感谢您的关注和收藏!!!!!!

image.gif 编辑

目录
相关文章
|
2月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
3月前
|
机器学习/深度学习 人工智能 搜索推荐
从零构建短视频推荐系统:双塔算法架构解析与代码实现
短视频推荐看似“读心”,实则依赖双塔推荐系统:用户塔与物品塔分别将行为与内容编码为向量,通过相似度匹配实现精准推送。本文解析其架构原理、技术实现与工程挑战,揭秘抖音等平台如何用AI抓住你的注意力。
774 7
从零构建短视频推荐系统:双塔算法架构解析与代码实现
|
3月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
520 1
|
3月前
|
算法 搜索推荐 Java
贪心算法:部分背包问题深度解析
该Java代码基于贪心算法求解分数背包问题,通过按单位价值降序排序,优先装入高价值物品,并支持部分装入。核心包括冒泡排序优化、分阶段装入策略及精度控制,体现贪心选择性质,适用于可分割资源的最优化场景。
304 1
贪心算法:部分背包问题深度解析
|
3月前
|
机器学习/深度学习 边缘计算 人工智能
粒子群算法模型深度解析与实战应用
蒋星熠Jaxonic是一位深耕智能优化算法领域多年的技术探索者,专注于粒子群优化(PSO)算法的研究与应用。他深入剖析了PSO的数学模型、核心公式及实现方法,并通过大量实践验证了其在神经网络优化、工程设计等复杂问题上的卓越性能。本文全面展示了PSO的理论基础、改进策略与前沿发展方向,为读者提供了一份详尽的技术指南。
粒子群算法模型深度解析与实战应用
|
3月前
|
机器学习/深度学习 资源调度 算法
遗传算法模型深度解析与实战应用
摘要 遗传算法(GA)作为一种受生物进化启发的优化算法,在复杂问题求解中展现出独特优势。本文系统介绍了GA的核心理论、实现细节和应用经验。算法通过模拟自然选择机制,利用选择、交叉、变异三大操作在解空间中进行全局搜索。与梯度下降等传统方法相比,GA不依赖目标函数的连续性或可微性,特别适合处理离散优化、多目标优化等复杂问题。文中详细阐述了染色体编码、适应度函数设计、遗传操作实现等关键技术,并提供了Python代码实现示例。实践表明,GA的成功应用关键在于平衡探索与开发,通过精心调参维持种群多样性同时确保收敛效率
机器学习/深度学习 算法 自动驾驶
607 0
|
3月前
|
机器学习/深度学习 人工智能 资源调度
大语言模型的核心算法——简要解析
大语言模型的核心算法基于Transformer架构,以自注意力机制为核心,通过Q、K、V矩阵动态捕捉序列内部关系。多头注意力增强模型表达能力,位置编码(如RoPE)解决顺序信息问题。Flash Attention优化计算效率,GQA平衡性能与资源消耗。训练上,DPO替代RLHF提升效率,MoE架构实现参数扩展,Constitutional AI实现自监督对齐。整体技术推动模型在长序列、低资源下的性能突破。
458 8
|
3月前
|
算法 API 数据安全/隐私保护
深度解析京东图片搜索API:从图像识别到商品匹配的算法实践
京东图片搜索API基于图像识别技术,支持通过上传图片或图片URL搜索相似商品,提供智能匹配、结果筛选、分页查询等功能。适用于比价、竞品分析、推荐系统等场景。支持Python等开发语言,提供详细请求示例与文档。
|
3月前
|
机器学习/深度学习 算法 搜索推荐
从零开始构建图注意力网络:GAT算法原理与数值实现详解
本文详细解析了图注意力网络(GAT)的算法原理和实现过程。GAT通过引入注意力机制解决了图卷积网络(GCN)中所有邻居节点贡献相等的局限性,让模型能够自动学习不同邻居的重要性权重。
541 0
从零开始构建图注意力网络:GAT算法原理与数值实现详解