Elliptic Curve Cryptography: a gentle introduction (2)


椭圆曲线加密:有限域和离散对数

这篇文章是ECC:优雅入门系列的第二篇文章

在前面的文章中,我们已经知道了椭圆曲线是如何在实数域内定义一个群的。特别地我们已经定义了一种点加的规则:给定三个齐次的点,它们的和为0 (P+Q+R=0)。我们已经通过一个几何方法和一种代数方法来描述计算点的加法。

然后我们介绍了一个扩展标量乘法(nP = P+P+…+P)我们也找到了一种较为简单的计算标量乘法的”简便“算法:double and add

现在我们将我们的椭圆曲线严格限制到有限域(finiite fields)中,而不是在实数域中,我们看看会有什么变化。

p的整数模域(The field of integers modulo p)

首先,有限域,是一个有限数字元素的集合。一个有限域的例子就是p的证书模。其中p是一个素数。这通常会被称为\mathbb{Z}/p,GF(p) 或者\mathbb{F}_p。我们会在后面用到这些符号。

在域中我们有两个双目运算,加法(+)和乘法( \times )。这两者都是闭集,满足结合律以及交换律。对于这两个操作,存在这样的唯一元素,有且仅有唯一的相反元素。最终,乘法可以分配到加法中:x\times (y+z) = x \times y+x \times z

这个p的整数模域包括了所有的从0到p-1的整数。加法和乘法也都能够在模运算中表现良好,这里有\mathbb{F}_{23}的一些样例操作:

  • 加法 (18 + 9)\mod 23 = 4
  • 减法 (7 - 14)\mod 23 = 16
  • 乘法 4\cdot7\mod 23 = 5
  • 相反加 -5\mod 23 = 18
    • 特别地: (5+(-5))\mod 23 = (5+18)\mod 23 = 0
  • 相反幂 9^{-1} \mod 23 = 18
    • 特别地: 9\cdot9^{-1}\mod 23 = 9 \cdot 18\ mod\ 23  = 1

如果这些等式对你来说不是很熟悉,那么你可能需要恶补一下有关模运算的有关知识,你可以到可汗学院学习一下。

前已经阐明,p 的模整数是一个域,并且其拥有的所有属性都已经列出。需要注意的是,p 必须是素数,这点非常重要。4的模整数就不是一个域:2没有相反幂(例如,等式 2\cdot x\mod 4 = 1没有解)

p的除法(division modulo p)

我们马上就要在\mathbb{F}_p上定义椭圆曲线,但是在做这件事之前,我们需要对在\mathbb{F}_p的上的除法有一个清晰的认识,我们可以简单地认为:x/y=x\cdot y^{-1},或者,简而言之,x除以y就等于x乘以y的相反幂,这个事实没有什么特别的,但是它给了我们最简单的得到除法结果的方法:找到一个数的相反幂,然后做一次简单的乘法。

计算相反幂有一个”挺简单“的方法,那就是采用extended Euclidean 算法,这个算法的时间复杂度是O(log_p)(或者O(k),如果考虑到位长度)在最差的情况下。

我不会展开对”extended Euclidean“算法的讲解,因为这和我们的主题无关,但我在这里提供了一个能够工作的python实现代码:

def extended_euclidean_algorithm(a, b):
    """
    Returns a three-tuple (gcd, x, y) such that
    a * x + b * y == gcd, where gcd is the greatest
    common divisor of a and b.

    This function implements the extended Euclidean
    algorithm and runs in O(log b) in the worst case.
    """
    s, old_s = 0, 1
    t, old_t = 1, 0
    r, old_r = b, a

    while r != 0:
        quotient = old_r // r
        old_r, r = r, old_r - quotient * r
        old_s, s = s, old_s - quotient * s
        old_t, t = t, old_t - quotient * t

    return old_r, old_s, old_t


def inverse_of(n, p):
    """
    Returns the multiplicative inverse of
    n modulo p.

    This function returns an integer m such that
    (n * m) % p == 1.
    """
    gcd, x, y = extended_euclidean_algorithm(n, p)
    assert (n * x + p * y) % p == gcd

    if gcd != 1:
        # Either n is 0, or p is not a prime number.
        raise ValueError(
            '{} has no multiplicative inverse '
            'modulo {}'.format(n, p))
    else:
        return x % p

\mathbb{F}_p上的椭圆曲线(Elliptic curves in \mathbb{F}_p)

现在我们已经先把所有需要的先修知识都进行说明了,现在我们可以把椭圆曲线转移到\mathbb{F}_p上了。在前文我们提到点集的描述是:

    \[\{(x,y) \in \mathbb{R}^2\ | y^2 \ =x^3 + ax + b , 4a^3 + 27b^2 ≠ 0 \} \cup \{0\}\]

现在变成:

    \[\{ (x,y) \in (\mathbb{F}_p)^2\ | \ y^2\equiv x^3 + ax + b (\mod p), 4a^3+27b^2 \not\equiv(\mod p) \} \cup \{0\}\]

其中0依旧认为是无限远的点,以及a和b是在\mathbb{F}_p上的两个整数。
elliptic-curves-mod-p

曲线 y^2 \equiv x^3−7x+10(\mod p) 其中点 p=19,97,127,487
需要注意的是,对于所有的x,当y=p/2,至多存在两个点。

singular-mod-p

曲线 y^2\equiv x^3(\mod 29) 是singler的,它有三个点在(0,0)。这不是一条有效的椭圆曲线。

前面描述的是连续的曲线,在xy平面上没有相交点,而且我们也可以证明,就算将其放到我们的有限域中,椭圆曲线在域\mathbb{F}_p依旧是一个阿贝拉群(abelian group)。

##点加(Point addition)
明显地,我们需要将我们的加法的定义改变一下,为了能够让它在域\mathbb{F}_p也能够工作得很好。在实数域下,我们称三个齐次的点之和为零(P+Q+R=0)。我们可以保留这个定义,但是在\mathbb{F}_p上,怎么样的三个点是齐次的呢?
如果有一条直线可以穿过三个点,那么我们可以将三个点称为齐次的,现在,我们当然不能和在\mathbb{R}一样定义。我们可以这样说,在\mathbb{F}_p上的直线是一个点的集合(x,y),这个点集满足条件ax+by+c\equiv 0 (\mod p)(这其实是一个标准的直线方程,我们就是加了”(\mod p)“而已。
Point addition for elliptic curves in Z/p

在曲线y^2 \equiv x^3− x + 3(\mod 127), 其中 P=(16,20)以及 Q=(41,120)上的点加. 注意,直线y \equiv 4x+83(mod127)是如何“重复”地在平面中相连的。

给定前提,现在在一个群中,点加仍然有如下我们已知的属性:

  • Q+0=0+Q=Q (这个由唯一元素(identity)定义可得)。
  • 给定一个非零点Q, 其相反数−Q是一个拥有相同的横坐标但是具有相反的纵坐标的点。或者如果你愿意的话,-Q = (x_Q,-y_Q \mod p) 例如,一个曲线在域\mathbb{F}_{29}上,有这样的一点Q=(2,5) ,那么其相反点-Q=(2,-5\mod 29)=(2,24)
  • 同样的,P+(-P)=0(从相反元素的定义可得)

代数和(Algebraic sum)

用代数方法计算点加和的方法和前文其实相同,除了我们需要在末尾加上” \mod p “修饰语。因此,给定P = (x_p,y_p),Q=(x_Q,y_Q)R = (x_R,y_R),我们可以通过下面的式子计算P+Q=-R

    \[x_R=(m^2-x_P-x_Q)\mod p\y_R=[y_P + m(x_R -x_P)]\mod p\=[y_Q + m(x_R -x_Q)]\mod p\]

如果 P\neq Q,斜率m可以通过如下公式得到:

    \[m=(y_P - y_Q)(x_P-x_Q)^{-1}\mod p\]

如果P=Q,我们有:

    \[m=(3x_p^2+a) \cdot (2y_p)^{-1} \mod p\]

这个公式并没有多大的变化并不是巧合,实际上这些公式在所有的域中都适用,有限域或者无限域(除了\mathbb{F}_2\mathbb{F}_3,这两个是特殊情况)。现在我感觉我需要提供一些证明,但是问题是,证明这个群法则需要用到一些比较复杂的数学概念。然而我找到了一个只用到了一些基础的概念的证明 proof from Stefan Friedl,如果你对证明这个公式为什么对几乎所有的域都适用感兴趣的话,可以阅读它。

回到我们的主题——我们不会说明几何方法:因为这中间存在一些问题。举例来说,在前面的文章中说,我们计算P+P我们需要得到曲线上在点P上的切线。但是在不连续的域上,再”切线“的概念就没有什么意义了,我们可以花点时间去解决它们,但是可能会比较复杂,并且不太实用。

但是,你可以通过交互工具这个我为了点加专门写的小程序来了解更多。

椭圆曲线的阶(The order of an elliptic curve group)

我们知道定义在有限域中的椭圆曲线具有有限个点,一个非常重要的问题待我们去解决:到底有多少点?
首先,我们把群里的点的个数称为群的阶(order)。

将x所有从0到p-1的可能值都试一下并不是用来计算点的个数的可行办法,以因为这需要O(p)步,如果p是一个大素数,那么这是一个”hard”问题。

幸运的是,我们又一个更快地计算群的阶数的算法:Schoof’s 算法,我们不想陷入这个算法的细节——我们只需要知道它能够在多项式时间内把阶数算出来,这就够了。

标量乘法和循环子群(Scalar multiplication and cyclic subgroups

)
在实数域中,乘法可以定位为:

    \[\underbrace{P+P+\cdots+P}_{n\ times}\]

然后,我们可以继续采用double and add algorithm来计算乘法,总计时间复杂度为O(log_n),(或者O(k)其中k是n的bit位数)。我也写了一个交互工具用于演示这个过程。
\mathbb{F}_p上的椭圆曲线的乘法是具有一些有趣的属性。我们拿曲线y^2\equiv x^3 +2x +3 (\mod 97)和其上的点P=(3,6)。然后我们计算一下P的乘法。
Cyclic subgroup

P=(3,6) 倍数只有五个独立的点(0, P, 2P, 3P, 4P) 这是一个不断循环的环。从中可以非常简单地看出在椭圆曲线上的标量乘法和模代数运算中加法的相似性。

  • 0P=0
  • 1P=(3,6)
  • 2P=(80,10)
  • 3P=(80,87)
  • 4P=(3,91)
  • 5P=0
  • 6P=(3,6)
  • 7P=(80,10)
  • 8P=(80,87)
  • 9P=(3,91)

从这里我们可以很快的看出两个特点:
1. P的倍数只有五种,其他在椭圆曲线上的点不会出现。
2. 他们是“重复的环”。

我们可以得出如下结论

  • 5kP=0
  • (5k+1)P=P
  • (5k+2)P=2P
  • (5k+3)P=3P
  • (5k+4)P=4P

适用任意的整数k。注意到这五个等式可以被“压缩”到一个等式,这要用到模运算符号:

    \[kP=(k \mod 5)P\]

不仅仅是这些,我们也可以快速地验证:这五个点在一个闭集中。换句话说,不管我们是加上0,2P,3P或者4P,得到的结果都是这五个点钟的某一个。再重复一遍,其它的椭圆曲线上的点将不会出现在结果中。

这个结论其实适用于所有的点,不仅仅是点P = (3,6)。实际上我们可以通过一个公式来描述通用的P :


    \[nP + mP = \underbrace{P+\cdots + P}_{n\ times}+\underbrace{P+\cdots+P}_{m\ times}= (n+m)P\]

这个公式可以描述为:如果我们将两个P的倍数相加,我们将会得到一个P的倍数,(例如,P的倍数是加法闭集的)。这点就足证明P的倍数是一个有椭圆曲线上的点形成的群的循环子群

“子群”是另一个群的子集,一个“循环子群”是一个所有的元素会循环重现的子群,就像我们前面展示的例子一样。那么这个点P就被称为这个循环子群的生成者(generator)或者基点(base point)。

循环子群是ECC和其它加密系统的基石。在下一篇文章中将会进行更加详细的解释。

子群的阶(Subgroup order)

我们可以问问我们自己由点P生成的子群的阶是多少(或者,相等的,P的阶是多少),为了回答这个问题,我们不能够采用前面提到的Schoof算法。因为这个算法只适用于椭圆曲线整个群中,而不能够在子群中工作。在解决这个问题之前,我们先修一点额外的知识:

  • 目前,我们定义了一个群的阶就是这个群中点的个数。这个定义还是有效的,但是在循环子群中,我们需要给一个新的等价定义:点P的阶是一个最下的能够让等式nP=0的正整数。实际上,如果你看到前面的例子,我们的子群包括5个点,而且我们有5P=0
  • P的阶在Lagrange’s theorem中有详细阐述,主要的意思是:子群的阶是父群的阶的一个因数,换句话说,如果一个椭圆曲线包括N个点,那么它的一个子群就包括n个点,而且,n是N的一个因数。

上面的两条特性结合起来我们能够找出一个基于点P的子群的阶:
1. 利用Schoof算法计算椭圆曲线的阶N
2. 找到所有N的因数
3. 对于所有N的的因数n,计算nP
4. 找到最小能够让nP=0成立的n,这就是子群的阶。

举一个例子:对于曲线

    \[y^2 = x^3 - x + 3\]

是在域\mathbb{F}_{37}上的曲线,它具有阶N=42,它的子群可能有如下的阶:n = 1,2,3,6,7,21或者42。如果我们尝试P = (2,3),我们可以看到P\neq0,2P\neq0,...,7P=0,因此点P的阶就是n=7

需要注意的是:一定要是最小的因数,而不是随意的一个。如果我们随便找一个,我们发现n=14也是成立的,但是只是P的一个倍数。

另一个例子:椭圆曲线定义在\mathbb{F}_{29}上,形式为y^2 = x^3 - x + 1,它的阶为 N = 37,这是一个素数。它的子群只可能有阶1或者37。正如你猜测的,当n=1时,子群只包括一个无穷点,当n=N子群包括所有椭圆曲线上的点。

找到一个基点(Finding a base point)

在我们的ECC算法中,我们需要一个高阶的子群。所以通常地,我们会选择一个椭圆曲线,并计算它的阶(N),选择一个大因数作为子群的阶(n)最后我们再去找一个合适的基点。也就是说,我们不会先选择一个基点再计算它的阶数,而是用相反的方式,先选择一个合适的阶然后在寻找相应的基点。那么我们是怎么做到的呢?

首先,我们需要加点料。Lagrange定理可以推出h=N/n一定是一个整数(因为n是N的一个因数)。这个h有一个名字叫做子群辅因子
现在对于椭圆曲线上的任意一点我们有NP=0。这是因为N是所有候选n的倍数。利用辅因子的定义,我们可以得出如下的定理:

    \[n(hP) = 0\]

现在假设 n 是一个素数(具体原因会在下一篇文章中解释,我们比较钟爱素数阶)。分析一下上面的公式,然后我们给出 G = hP,这个公式可以得到一个阶为n的子群(除了 G = hP = 0,这个时候子群的阶为1)。

根据这个我们可以给出算法的大纲:

  1. 计算椭圆曲线的阶N
  2. 选择一个合适的子群阶n,为了算法能够工作,这个数必须是一个素数且必须是N的一个因数。
  3. 计算辅因子 h = N/n
  4. 在曲线上选择一个随意的点P
  5. 计算G = hP
  6. 如果G是0,那么重复第4步。直到我们找到一个子群的基点 能够让这个子群的阶为n以及其辅因子为h。

注意这个算法只能够在n为素数的时候工作,如果n不是素数,那么G的阶将会是n的一个因数。

离散对数(Discrete logarithm)

正如我们在连续的椭圆曲线中讨论的,如果我们已知P和Q,那么如何知道这样的k使得Q = kP

这个问题就是我们将要讨论的椭圆曲线上的椭圆曲线问题,这被称为”hard”的问题,目前还没有能够利用经典计算机在多项式时间内计算出来的算法。但是也没有能够证明该难度的数学证明。

这个离散对数问题也在其他加密系统中有相当的应用,例如数字签名算法( Digital Signature Algorithm ,DSA),Diffie-Hellman密钥交换算法和ElGamal算法——他们用相同的算法绝非偶然。不同的是,在我们的离散对数系统中需要将模运算代替原来的标量乘法,那么离散对数问题就可以用下面的问题描述:我们已知a和b,是否能够求得这样的k使得b = a^k \mod p?

这些问题都是“离散的”,因为他们限制在有限域(更加精确的,循环子群)中,并且也是“对数”的,因为它和通常的对数算法相似。

那么是什么让ECC这么青睐离散对数问题呢?就现在而言,主要原因是:在椭圆曲线上的离散对数问题是”harder”的,相对于其它相似的应用在密码学中的问题而言。同其它加密系统相比,在相同的安全级别上,它可以节约整数k的位数。更多的细节我们会在第四篇文章中进行阐述。

未完待续

下一篇文章将是这个系列的第三篇文章,它将介绍ECC算法:包括密钥对生成,ECDH和ECDSA。这将是这个系列中最有趣的一篇,不要错过!

转载请注明出处

Elliptic Curve Cryptography: a gentle introduction (1)


众所周知的公钥加密算法包括,ECC,ECDH或者是ECDSA。其中ECCElliptic Curve Cryptography (椭圆曲线公钥加密)的缩写,而其它的算法都是在其基础上开发的。

现在我们可以在TLS,PGP,SSH等应用中看到椭圆曲线加密系统的踪影,这三个应用几乎构建起了现代web应用和信息技术世界的基石,更不要说Bitcoin以及其他的加密货币。

在ECC流行之前,几乎所有的公钥算法都是基于RSA,DSA以及DH,这些算法都是基于同余理论构建的。RSA以及其同类算法现在还是很流行,往往配合ECC一同使用,相对于RSA这种原理很容易被人理解,也很容易实现的算法而言,ECC的内部机理对大多数人而言似乎是一种未解之谜。

我将会用这一系列的文章带领大家进入椭圆曲线加密的全新世界,我的目标不是详细地说明ECC的全部细节(这些在网上随手都能搜索到),而是要提供一个简单易懂的教程说明什么是ECC,以及为什么它是安全的,当然我也不想花费大量的时间去进行数学证明。我将会提供一些有用的样例然后用一些生动的动态交互工具和脚本去展现它们。

特别地,这里有些点事我将要提及的:

为了理解这里都在说些什么,你需要预先理解一些理论:几何和现代代数,并且需要了解对称加密和非对称加密算法,最后你需要对什么是easy的问题,什么是hard的问题有一个清晰的认识。

准备好了吗?让我们开始吧!

椭圆曲线 (Elliptic Curves)

首先,从什么是椭圆曲线(Elliptic Curver)开始,Wolfram MathWorld给了一个完整定义: 但是我们不玩这个,简单来说,椭圆曲线就是一个可以通过等式:

    \[y^2 = x^3 + ax + b\]

描述的点集。

其中

    \[4a^3 + 27b^2 \ne 0\]

因为需要排除掉 singular curves 也称奇异曲线。

上述的等式叫做椭圆曲线Weierstrass normal form

curve1

上图是不同椭圆曲线的形状( b=1, a从2变化到-3 )

singularities

singularities 曲线:

左边, a curve with a cusp(尖点):

    \[y^2=x^3\]

右边, a curve with a self-intersection(自交)

    \[y^2=x^3 - 3x+2\]

上述两者均为不合法的椭圆曲线

根据不同的a和b,椭圆曲线可能在平面上展现出不同的形状,很明显,椭圆曲线是关于x轴对称的。

在我们的设计当中,我们还需要一个无穷点 Point at infinity(或者称为理想点),现在我们用0作为我们的无穷点。

我们将上面的椭圆曲线的定义再明确一下,并加入刚刚的无穷点,我们可以得到如下的公式:

    \[\{\,(x,y) \in \mathbb{R}^2 \mid y^2=x^3+ax+b, 4a^3+27b^2 \neq 0 \,\} \cup \{\,0\,\}\]

群(Group)

群(Goup)在数学上的定义是能够进行所谓“加法”的二元运算的一种集合,通常我们将这种运算用符号+来表示。如果集合\mathbb{G}想要成为一个”群”,它必须有以下四个属性:

  1. 闭包(closure)律:如果ab都是集合\mathbb{G}的成员,那么a+b也是集合\mathbb{G}的成员;
  2. 结合律(associativity( a + b ) + c = a + ( b + c )
  3. 需要存在一个孤立点(identity element0 满足 a + 0 = 0 + a = a;
  4. 每个元素都有一个相反数,例如所有的元素a都存在这样的元素b使得a + b = 0

    如果这个群还满足:

  5. 交换律(commutativity): a + b = b + a

    这个群就被称为abelian group

按照我们对加法的传统理解,我们可以得出以下结论:整数集合\math{Z}是一个群(而且是一个阿贝尔群(abelian group)),但是自然数集合ℕ不是一个群,它不满足第四条属性。

群可以说是非常的nice,因为如果我们证明了上述四条属性的正确性,那么我们可以免费得到一堆有用的属性,例如如果一个独立元素是唯一的那么其一定有一个相反元素也是唯一的,换句话说,对任意的元素a都存在唯一的元素b使得a+b=0当然我们也可以写作b=-a,不管是直接的还是间接的,这些定理都将在后面的内容中起到非常重要的作用。

椭圆曲线的群律(The group law for elliptic curves)

我们可以在椭圆曲线上找到一个群,这个可以描述为:

  • 群中的所有元素都是椭圆曲线上的点。
  • 孤立点是无穷0
  • 其中点P的相反数是另一个相对于X轴对称的点。
  • 加法遵从以下规则:给出三个在一条直线上的非零点P,Q,R,三个点之和P+Q+R=0

three-aligned-points

三个点之和为0

需要注意的是最后一条规则,我们仅仅需要三个点,这三个点需要在一条直线上,但是不需要关心他们的顺序,也就是说,如果P,QR在一条直线上,那么:

    \[P+(Q+R)=Q+(P+R)=R+(P+Q)=\cdots =0P+(Q+R)=Q+(P+R)=R+(P+Q)=\cdots =0\]

显然,我们的 + 运算符同时满足结合律(associative)和交换律(commutative),这其实是个阿贝尔群。

到此为止,一切都很棒!但是,我们到底应该怎么去计算两个任意点的和呢?

几何加法

多亏了阿贝尔群的定理,我们可以得到下列的结果:P + Q + R = 0 => P+Q = -R。利用这个等式,我们可以利用几何方法去计算PQ两个点的和:如果我们画一条穿过P点和Q点的直线,这条直线将会和椭圆曲线相交于第三个点R(这其实隐含在P,Q,R在一条直线上这个前提中).如果我们取R的相反数-R,这个就是我们要的 P+Q的结果。

point-addition

画一条穿过P点和Q点的线,这条线将会穿过点R,而R的对称点-R就是P+Q的结果。

这个几何方法是行得通的,但是我们还是需要细化一下,尤其是我们需要回答几个问题:

  • 如果P=0或者Q=0?显然我们没有办法画出一条线(因为0不在xy平面上),但是我们的定义是0是我们的孤立点,P+0=P以及Q+0=Q,这个对任意的PQ都成立。
  • 如果P = -Q?在这种情况下,穿过两点的直线是垂直的,而且不会与椭圆曲线相交于第三个点,但是因为P是Q的相反元素,我们有P+Q = P+(-P) =0这条定理。

  • 如果P = Q?在这种情况下,可以画出无数条穿过两点的现,这样让事情变得有点复杂,所以我们考虑一种简化情况,Q′\neq P,如果Q'无限接近P,将会发生什么?

animation-point-doubling

随着两个点越来越接近,这条线渐渐变为了椭圆曲线的切线

随着Q'无限趋近于P,穿过pQ'的线渐渐变成了曲线的切线,换句话说,我们可以说p + p = -R,其中R是曲线和曲线在P点的切线的交点。

  • 如果P≠Q但是恰好又没有第三个点R怎么办?这种情况其实很像上面的那种情况,实际上这种情况其实就是经过P,Q两点的直线恰好是曲线的切线。

    animation-tangent-line

    如果我们的直线交于两点,换句话说,这条直线是曲线的切线,显然,最终结果是两点中的某一点的对称点。

    我们假设P是切点,在上面的情况中,我们可以得到P+P=-Q,可以转变为:P+Q=-P,如果,在另一种情况下,Q是切点,正确的等式将会变为P+Q=-Q

代数加法(Algebraic addition)

如果我们让计算机做上述的点加运算,我们需要将上述的几何加法转变为算术加法,将上面的规则转换为用一组公式来描述看上去非常简单,实际上确是非常乏味的,因为它要求解三次方程。所以我们跳过无聊的部分,直接给出结果。

首先我们先排除烦人的特殊情况。我们已经知道P+(-P)=0,而且我们也知道P+0=0+P=P,所以在我们的公式中,我们仅仅考虑非零,非对称的两个点,P=(x_P,y_P)Q=(x_Q,y_Q)

如果PQ是不同的(x_P≠x_Q),那么穿过这两点的线的斜率是:

    \[m=\frac{y_P−y_Q}{x_P−x_Q}\]

这条直线和椭圆曲线的交点是第三点R(x_R,y_R)

    \[x_R=m^2−x_P−x_Q\]

    \[y_R = y_P + m(x_R - x_P)\]

或者,相等地:

    \[y_R=y_Q+m(x_R−x_Q)\]

因此,(x_P,y_P)+(x_Q,y_Q)=(x_R,−y_R) (请注意符号并谨记 P+Q=-R)

如果我们想要检查这个结果是否是正确的,我们需要检查R是否在曲线上,以及P,Q,R是否在一条直线上。检查三个点是否在一条直线上比较琐碎。但是检查R是否在曲线上还是比较简单的,我们需要解三次方程,当然还是很无趣。

所以我们换种方式,我们用例子来验证一下,根据我们的visual tool,给出P = (1,2)和Q = (3,4),这两个点都是在曲线:

    \[y^2 = x^3 -7x +10\]

上的,这两点的和是P+Q=-R=(-3,2),让我们看看等式是否成立:

    \[m = \frac{y_P-y_Q}{x_P-x_Q}= \frac{2-4}{1-3} = 1\]

    \[x_R = m^2 -x_P-x_Q = 1^2 -1-3 = -3\]

    \[y_R = y_P + m(x_R-x_P)=2+1·(-3-1)=-2   =y_Q+m(x_R-x_Q)=4+1·(-3-3)=-2\]

确实是正确的。

我们注意到,这些等式在P点或是Q点是切点的时候也是work的。

让我们试试P=(-1,4)Q=(1,2)

    \[m = \frac{y_P-y_Q}{x_P-x_Q}=\frac{4-2}{-1-1}=-1\]

    \[x_R = m^2 -x_P-x_Q = (-1)^2 - (-1)-1 = 1\]

    \[y_R = y_P + m(x_R-x_P)=4+-1·(1-(-1))=2\]

我们通过可视化工具visual tool也可以得到同样的结果。

P=Q的情况需要稍稍特殊对待:求x_R和y_R的方程和上面是一样的,但是对于x_P=x_Q这种情况,我们需要换一个求斜率的公式:

    \[m = \frac{3x^2+a}{2y_p}\]

注意到,就像我们所期待的,这个用来计算m的表达式是由以下公式派生的第一个式子:

    \[y_p = ±\sqrt{x_P^3+ax_P+b}\]

为了证明这个结果的有效性,只需要证明R是否是曲线上的点,以及经过PR两点的是否与曲线有且仅有两个焦点。但是我们不去证明这点,我们还是通过一个例子来说明,降低难度:

P=Q=(1,2)

    \[m = \frac{3x_P^3 +a}{2y_P} = \frac{3· 1^2-7}{2·2}=-1\]

    \[x_R = m^2 -x_P -x_Q = (-1)^2 -1-1=-1\]

    \[y_R = y_R +m(x_r - x_P) = 2+(-1) ·(-1-1) = 4\]

我们已经知道答案的情况下(P+P=-R= (-1,-4)),这是正确的(就不要纠结是怎么预先得到答案的,原作者为了降低难度,简单示例了一下,想要了解更多,点击链接即可,ChenQuan注)

标量乘法(Scalar multiplication)

在加法的基础上,我们可以定义一个新的操作:标量乘法(scalar multiplication),可以表示为:

    \[nP=\sum{P_1+P_2+\cdots +P_n}\]

其中n是自然数,我也写了一个可视化工具用来演示标量乘法,你当然也可以试试。

就从公式上看,看上去计算nP需要n次加法运算,假设n拥有k个二进制数字,我们的算法复杂度将会是O(2^k),当然这有点不太ok,但是实际上还有更加高效的算法。

其中有一种算法叫做 double and add算法,这种算法的理论可以通过例子更好地进行解释。假设我们有一个数字n = 151,它的二进制值是:10010111。那么这个二进制值可以通过2的幂次和进行计算:

    \[151 = 1\cdot 2^7 +0\cdot 2^6 +0\cdot 2^5+1\cdot 2^4+0·2^3 +1\cdot 2^2+1\cdot 2^1+1\cdot 2^0=2^7+2^4+2^1+2^0\]

(我们通过将n的每一位二进制数n乘以一个2的幂次)将n表示出来:

也就是说,我们可以得到:

    \[151\dot P = 2^7·P +2^4·P+2^2·P+2^1·P+2^0·P\]

double and add 算法主要步骤如下:

  • 得到一个P
  • 将P乘以2所以我们得到2P
  • 将2P+P(为了得到2^1P+2^0P
  • 再将2P乘以2得到2^2P
  • 将其相加得到2^2P + 2^1P+2^0P
  • 将2^2P乘以2得到2^3P
  • 不要将2^3执行相加步骤
  • 将2^3P乘以2得到2^4P
  • 将其加上我们的结果(所以我们得到了2^4P+2^2P+2^1P+2^0P)

最后,我们可以通过double and add算法计算出151·P的结果

如果这还不够清楚,那么这里有一个python脚本实现了这个算法:

def bits(n):
    """
    Generates the binary digits of n, starting
    from the least significant bit.

    bits(151) -> 1, 1, 1, 0, 1, 0, 0, 1
    """
    while n:
        yield n & 1
        n >>= 1

def double_and_add(n, x):
    """
    Returns the result of n * x, computed using
    the double and add algorithm.
    """
    result = 0
    addend = x

    for bit in bits(n):
        if bit == 1:
            result += addend
        addend *= 2

    return result

如果doubleadd的复杂度均为O(1)那么这个算法的复杂度为O(log n)或者为O(k)如果这个bit的长度是确定的),这非常棒。这比原来的O(n)算法好多了

对数(Logarithm)

给定的nP,我们至少能够在一个多项式时间内将Q = nP计算出来,但是如果反过来呢?如果我们预先知道Q和P然后需要算出n?这个问题就是典型的对数问题,我们将之称为”对数“而不是”除法“是为了整合其他的加密系统(同样的我们也用幂来取代乘法)。

我并不知道任何用来解对数问题的”easy“算法,然而playing with multiplication 展现了一些简单的模式。举例而言:现在有一个曲线 y^2 = x^3-3x+1 以及其上的点 P=(0,1) 。我们可以快速地验证是否正确。如果n是奇数,nP就在曲线的左半平面;如果n是偶数那么nP就在右半平面。如果我们做一些更加深入的实验,我们可能会找到更多的套路,最终能够带领我们写出一种能够在曲线上高效计算对数的算法。

但是这里仍然存在很多对数问题:离散问题(the discrete logarithm)。如果我们减小我们椭圆曲线的域,那么纯量相乘仍然是”easy”的,而离散对数却是”hard”问题,这个对偶关系这正是椭圆曲线加密系统最重要的一块砖瓦。

待续

接下来我们将会讨论有限域(finite fields)以及离散对数问题,敬请期待。

参考文献:
http://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/

一个成功的git分支模型


A successful Git Brabching model

在这篇文章中我将介绍一些在过去一年中(无论是工作还是个人项目中)较为成功的开发模型,这里不会介绍很多项目的细节,仅仅是介绍分支策略和发布管理。

git-model@2x

整个模型都是专注于Git 作为一个源代码版本管理工具进行的。

Why git

尽管Git和中央源代码管理系统之间的优劣讨论从未停止过,期间的争论也很激烈,但是作为一个开发者,我更习惯用Git作为我的版本管理工具,Git彻底改变了开发者合并和分支的思维习惯。在传统的CVS/Subversion系统中 ,合并分支是一件非常恐怖的事情,你需要非常小心。

但是在Git中,这些行为变得非常地简单并且安全,这几乎变成了程序员每天工作流中的核心部分。就拿书来说,讲CVS/Subversion系统的书中,分支和合并几乎是在后面的章节中进行介绍的(为高级用户准备的)但是在几乎所有介绍Git的书中,分支和合并的内容都放到了前三章作为基础内容进行介绍。

Decentrailzed but centrailzed

(标题我译为分布且集中,但是好像并不是很恰当)

在我们的日常工作中,工作较好的模型是存在一个中心化的truth”(可信)仓库,需要注意的是,这个仓库仅仅是在逻辑上被设置为一个中央仓库(因为Git是一个DVCS<分布式版本控制系统>,它在技术层面并没有一个实际意义上的中央仓库)我们将这个“中央”仓库称为origin,几乎所有的Giter都对这个名字非常熟悉。
centr-decentr@2x

所有的开发者都从origin 拉取代码,并将修改push到origin仓库中。除了到中央仓库push-pull之外,开发者还可以从其他的子团队分支中拉取代码。举例来说,在开发一个非常重大的feature的时候,可能会有多个开发者共同合作,很多时候push到“中央”仓库可能还太早,这个时候这些子团队分支就起到作用了。就像上图所示,这些子团队分支就像Alice-Bob,Alice-David和Clair-David子团队分支。

从技术上来说,让Alice 定义一个新的名叫Bob的远程分支,并将其指向Bob的仓库,并不需要多少成本,反之亦然。

The main branches

(主分支策略)

这个开发模型在很大程度上是由现有的模型演变而来,就像下图所示。核心仓库有两个无限生命周期的分支:

  • master
  • develop

origin仓库的master分支相信对所有的Git user一定非常熟悉,与master分支同时存在的分支并行发展,被称为develop分支。

main-branches

我们通常将origin/master分支作为源代码的HEAD,并将其标记为production-ready(可供发布)状态。

我们把origin/develop分支作标记为最新开发进度的HEAD,所有在develop分支上所做的改变都将体现在下个发布版本中。有的人将这个分支为“集成分支”,很多自动化的预发布版本都是从这个分支编译而来。

develop分支上的源代码达到了一个可以发布的点的时候,所有的变更都将以某种方式合并回master并将打上一个发布tag。当然具体是怎么做的将在今后进行讨论。

因此,每次将变更合并到master就意味着新的生成版本发。所以这件事需要非常严格地进行审核,从理论上讲,我们可以在每次commitmaser分支的时候,用git hooks进行自动化编译,并自动化地将我们的软件发布到我们的生产服务器。

Supporting branches

除了main分支和develop分支,我们的开发模型还拥有很多支持分支来帮助团队成员之间进行协作,这些分支可以方便跟踪新特性,为生产发布做准备和快速热修复产品中的问题。不像前面提到的主要分支,这些分支最终都会本删除,所以这些分支的生命周期是有限的。

支持分支主要分为以下三类:

  • Feature branches
  • Release branches
  • Hotfix branches

这些分支都有其自身的目标,并遵守相应严格的规则去确定哪个分支是其的源分支,那些分支是其需要合并进入的分支。

实际上从技术层面这些分支和普通分支一样并不是特殊的分支。这些分支的分类取决于我们如何去使用它。这些分支实际上就是普通的Git分支。

Feature branches

可能检出的分支:

  • develop

需要并入的分支:

  • develop

分支可以命名为:

除了:master,develop,release-*或者hotfix-*之外的名称

fb@2x

Feature分支(有的时候也成为主题分支)是在开发新的特性或者是发布新的版本的时候使用的。当开始一个新的特性的开发的时候,往往新特性的内容在当时是不可见的,但是实质上,feature将会一直存在直到该feature开发完毕,最终将会被合并回develop分支(为了能够真正地将新特性加入到上游分支,)或者被废弃(例如令人失望的尝试)。

Feature 分支往往只存在在开发仓库中,而不是在origin仓库中。

Creating a feature branch

当你需要开始开发一个新的feature的时候,你可以从develop分支检出新的feature分支:

$ git checkout -b myfeature develop

此时将会切换到新的分支 "myfeature"

在develop分支中加入新的feature

当你结束一个新的特性开发之后,往往需要将该分支合并到develop中将新特性真正加入到上游发布版本中:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

这里的no-ff选项往往会通过创建一个新的commit开进行合并,就算这个合并能够用fast-forward方式进行处理。这样就可以避免丢失一些在开发过程中的提交历史信息,通过这种方式能够正确地组织相应的commit以及将feature很好地进行合并。我们可以通过下图进行比较理解:

merge-without-ff@2x

在后面的例子中,我们是无法看到在实现分支的时候的所有提交历史的,你只能通过阅读相应的log开确定提交历史,当然回滚整个feature(例如一组commit)变成了一件非常头痛的事情,当然如果你用课no-ff选项,这些事情都变得很简单。

当然,这会创建一些新的(空的)commit,但是得到的好处远远能够抵消这点不足。

Realease branches

可能由以下分支检出:

  • develop

必须要合并回以下分支:

  • develop
  • master

分支命名规则:

  • release-*

Release分支为新产品的发布做准备,其允许做一些一些最终的修改(last-minute dotting of i’s and t’s)。进一步说明,该类型的分支,允许少量的bug-fix以及添加一些为发布准备的说明性信息(例如版本号,编译日期等等),当release分支上的所有工作都做完之后,develop分支就可以完全为下一个大型的release接受新的提交了。

这里有一个比较关键的时间点,就是何时从develop分支检出新的release分支,这个时间点往往是develop分支已经能够完全反映当前发布版本所需要的所有特性。此时至少所有的需要在发行版本中所包含的(release-to-be-build)特性都已经被合并到develop分支中了,需要提一下的是,所有下个版本的新特性都不能够合并到develop分支,直至新的release被检出(branch off)。

显然,发布版本号是在为了即将到来的新的发布版本开启一个新的release分支的时候指定的——换句话说不要太早。这样做的原因是,当develop中有一些被标记为next release的变更,但是并不明确next release最终会变成0.3还是1.0,只有release分支开始才被确定。一个新的release分支的启用往往是在版本号被确定之后。

创建一个release分支

发布分支是从develop分支中创建的。举例来说,当前的生产分支是1.1.5,这个时候有一个大的发布版本即将发布。此时develop分支应该应该已经准备好并处于next release状态,这个时候我们应该已经确定了具体的发布版本号为1.2(而不是1.1.6或者2.0),所以我们检出新的分支,并给予发布分支一个名称用于标识新的版本号。

$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)

在创建一个新的分支并切换到该分支之后,我们运行了一个bump-version.sh的脚本,这个脚本将会修改一些文件并让目前的工作空间变成能够反映新的版本特性。(当然这些修改也可以手动进行——这里的重点是需要进行一些修改)然后,这个已经被确认的版本号就会被提交。

结束一个release分支

当一个release分支已经准备好成为一个真正的发布版本,一些相应的动作需要被执行。首先这个发布分支需要合并到master分支当中(切记,所有提交到master分支上的变更都是可发布的)。然后,这个master分支上的commit应该打一些标记便于将来快速查询,当然这些信息需要简单易懂。

最后,这些在release分支上的变更应该合并回develop分支,这样在后面的分支才能够拥有在这个release分支上的bugfix

前两步的命令如下:

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2

目前,release分支已经完成了它的使命,并打了一个tag便于今后查询。

说明,你也可以利用-s或者-u命令为你打的tag进行一些数字签名。

为了保有在release分支上的变更,我们需要将这些变更合并回develop分支。当然,用git命令:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)

这些步骤可能引起一些合并冲突(当然这是很正常的,因为我们已经修改了版本号)。如果这样,就fix这些冲突,并commit它。

到这里为止,这个release分支真真正正完成了它所有的使命,这个时候我们就可以把这个分支删除了,因为它已经失去了利用价值了。

$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

Hotfix分支

可能检出的分支:

  • master

需要并入的分支:

  • develop和master

分支可以命名为:

hotfix-*

hotfix-branches@2x

Hotfixrelease分支十分相似,因为它们都是为了新产品发布而准备的,尽管这个分支往往是计划外的。它们往往会在一个非修复不可的,非常紧急的或者不期望看到的行为或者bug的时候生产版本中诞生。当生产版本上一个非常严重的bug需要立即修复的时候,一个hotfix分支就被检出了,这个分支可以从master分支的相应tag中检出。

这样做的关键在于,在develop分支上工作的团队不需要中断当前的工作,与此同时,另一个人可以快速修复生产版本上的bug。

创建一个hoxfix分支

Hoxfix分支是从master中诞生的,举例来说,当前的生产版本是1.2,而且该版本在实际业务中正运行着,但是有一些bug需要修复,而此时在develop分支上的版本还不稳定。我们就可以检出一个hotfix分支来解决这个问题。

$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

不要忘记将该版本号进行标记。

然后修复bug并通过一个或多个commit进行提交。

$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)

结束一个hotfix分支

当bug结束修复,这个bugfix分支需要重新合并到master分支中,而且也要同时合并到develop分支中,这是为了确保这些bugfix能够真正合并到下个发布版本中。这里就和结束release分支很像了。

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1

说明,你也可以利用-s或者-u命令为你打的tag进行一些数字签名。

然后将bugfix分支合并到develop分支中:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)

这里有一个例外,如果此时有一个release分支存在,这个hotfix就需要合并到release分支中,而不是develop分支。将hotfix合并到release分支中,是因为,在release分支结束的时候,最终也会合并入develop分支中,这样最终的结果也是讲bugfix安全地合并到了develop分支中。

最后删除hotfix分支:

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).

总结

虽然在这个分支模型中,没有什么令人震惊的奇技淫巧,但开篇的那个大图所标示的分支模型已经被证明在实际开发中能够起到非常大的作用。这个模型提供了一个优雅的协作范式,它易于理解,并能够让整个团队一直保持易于理解并便于协作的状态。

这里有一副PDF版本的高质量模型图,将它下载下来并作为一个快速查询图用吧!

当然这里还有一个gitflow的keynote,你可以下载下来用哦;)

Sublime Text 安装配置,代理设置,插件管理


 

步骤1: 下载并且安装

你可以从以下链接下载最新版本:

目前我使用的版本是ST3 build 3065 更新于2014年8月29日

译者 用的版本是st3 build 3083

步骤2: 安装Package Control (插件管理工具)

如果想安装其他的插件,需要先安装这个Package Control 插件,请遵照这个链接中的安装教程:

Package Control Install

注意:如果你在使用代理,可能需要手动下载并安装这个包,安装完成之后,需要重启下sublime text (出于安全因素的考虑)

Sublime Text 安装配置,代理设置,插件管理

Sublime Text – Installation and Configuration (English)

我一直想写一篇文章,用来说明如何按照我自己的喜好来进行Sublime Text(目前版本是V3)的安装和设置。
这篇文章更多的是为我自己写的一篇指南,以免未来的什么时候我忘记了。如果这篇文章能够帮到你,那就更棒啦!

步骤1: 下载并且安装

你可以从以下链接下载最新版本:

目前我使用的版本是ST3 build 3065 更新于2014年8月29日

译者 用的版本是st3 build 3083

步骤2: 安装Package Control (插件管理工具)

如果想安装其他的插件,需要先安装这个Package Control 插件,请遵照这个链接中的安装教程:

Package Control Install

注意:如果你在使用代理,可能需要手动下载并安装这个包,安装完成之后,需要重启下sublime text (出于安全因素的考虑)

译者
由于考虑到国内不一定能打开安装链接,我把安装代码贴在下面,请在st3中按快捷键’ctrl+`’然后再弹出的输入框中输入以下代码并回车(2015/8/25):

import urllib.request,os,hashlib; h = 'eb2297e1a458f27d836c04bb0cbaf282' +</blockquote>
'd0e7a3098092775ccb37ca9d6b2e4b7d'; pf = 'Package Control.sublime-package';
ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) );
by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest();
print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)

更新: 这个脚本是每天更新的,复制过去脚本会失效,请用上面的安装链接践行安装。(2017-04-01)

步骤2(附): Package Control的代理设置

如果你需要在代理环境中使用Sublime Text ,那么你需要配置一下代理来让Package Control 正常工作。

将以下代码加入到
Preferences > Package Settings > Package Control > Settings – User
中:


//proxy settings "http_proxy": "your.proxy.fqdn:80", "https_proxy": "your.proxy.fqdn:80", "proxy_username": "my_username", "proxy_password": "my_password",

注意:
你可能需要修改80端口为别的你代理的端口(比如8080), 你可以在IE的代理设置中找到这个端口 (译者用的是ss,视实际情况而定)。

完成之后,重启下Sublime Text

步骤3: 安装Sublime Text的插件

现在,你可以安装所有能让Sublime Text更酷的插件! 以下的步骤是安装所有插件需要的步骤:

  1. Cmd+shift+P (OSX) / Ctrl+Shift+P (Win/Linux)
  2. 输入:Install Packsge
  3. 搜索你需要的插件名称
  4. 按回车进行安装

我在Sublime Text中使用的插件有:

  • CSS Comb
  • Emmet<sub>1</sub>
  • Emmet CSS Snippets
  • FileDiffs (only on Windows machines)
  • Gist
  • Predawn<sub>2</sub>
  • PowerShell
  • SASS
  • SCSS
  • Sidebar Enhancements
  • SublimeLinter
  • VBDotNet
  • vbScript
  • WordPress

1: To use Emmet you need PyV8 installed. By default when installing Emmet, PyV8 will attempt to download and install automatically. If it doesn’t you an download it from here Emmet PyV8.
如果想要使用emmet插件需要安装PyV8依赖,一般情况下可以自动安装完成,如果它傲娇了,请务必点击上面的链接下载自行安装。

2: You must install Predawn prior to configuring User Settings in Step 5 below (otherwise the settings in the Colour Scheme & Theme section will fail).
For more information about PreDawn and the options available have a look here Predawn GitHub
如果你想要更改颜色主题,请一定要按照步骤5中的用户配置进行相应配置。

步骤4: 编辑asp页面以包含aspx 文件

由于这部分并不重要,是作者自己个人的偏好,并没有普遍性,所以不翻译了

步骤5: Sublime Text的用户设置:

想要改变SublimeText的默认设置,你需要把你的个人设置添加到User Settings文件中,你可以在Preferences &gt; Settings – User找到并编辑这个文件:

下面的是我自己添加的:

// Colour Scheme & Theme (for ST3)

"color_scheme": "Packages/User/predawn (SL).tmTheme",
"theme": "predawn-DEV.sublime-theme",

// Typography

"font_face": "Source Code Pro",
"font_size": 13,
"font_options": ["no_round"],
"highlight_line": true,
"caret_extra_width": 1,
"caret_style": "phase",
"tab_size": 2,
"translate_tabs_to_spaces": true,
"word_wrap": false,

// Whitespace, Matching, Copy & Auto-Complete

"copy_with_empty_selection": false,
"drag_text": false,
"match_brackets_content": false,
"match_selection": false,
"match_tags": false,
"translate_tabs_to_spaces": true,
"trim_trailing_white_space_on_save": true,

// Interface & Behavior

"close_windows_when_empty": false,
"draw_minimap_border": true,
"enable_tab_scrolling": false,
"hot_exit": false,
"overlay_scroll_bars": "enabled",
"open_files_in_new_window": false,
"preview_on_click": false,
"remember_open_files": false,
"scroll_past_end": true,
"scroll_speed": 5.0,
"show_full_path": false,

// Other Settings

"ignored_packages":
[
"Vintage"
],

注意:上面的是Sublime Text 3的设置,如果你正在使用ST2你需要把Colour Scheme & Theme 部分修改成下面的

//Colour Scheme Theme (for ST2)
"theme": "predawn.sublime-theme",
"color_scheme": "Packages/Predawn/predawn.tmTheme",

步骤6: 改变Sublime Text的图标

现在有很多的Sublime Text的炫酷图标,我也把我自己的改掉了,你可以按照下面的步骤进行修改:

Mac OSX

略(有兴趣请大家翻原文看)

Windows8

  1. 把新的图标拷贝到安装目录下(我的是D:\SublimeText3\)
  2. 右键点击 Sublime Text.exe
  3. 点击创建快捷方式
  4. 重命名快捷方式
  5. 右键点击快捷方式并选择属性
  6. 选择快捷方式栏
  7. 点击更改图标
  8. 选择新的图标
  9. 点击ok
  10. 右键点击快捷方式并放到开始中
    > 尼玛简直太感动太详细了,我居然翻译完了。。。)

步骤7: 安装Sublime Text 的许可

土豪请随意购买许可。

原文是教你如何购买许可的,当然这没啥意思,所以我找了几个许可大家随意取用(土豪请务必购买正版,请支持正版):

—– BEGIN LICENSE —–
Andrew Weber
Single User License
EA7E-855605
813A03DD 5E4AD9E6 6C0EEB94 BC99798F
942194A6 02396E98 E62C9979 4BB979FE
91424C9D A45400BF F6747D88 2FB88078
90F5CC94 1CDC92DC 8457107A F151657B
1D22E383 A997F016 42397640 33F41CFC
E1D0AE85 A0BBD039 0E9C8D55 E1B89D5D
5CDB7036 E56DE1C0 EFCC0840 650CD3A6
B98FC99C 8FAC73EE D2B95564 DF450523
—— END LICENSE ——
—– BEGIN LICENSE —–
K-20
Single User License
EA7E-940129
3A099EC1 C0B5C7C5 33EBF0CF BE82FE3B
EAC2164A 4F8EC954 4E87F1E5 7E4E85D6
C5605DE6 DAB003B4 D60CA4D0 77CB1533
3C47F579 FB3E8476 EB3AA9A7 68C43CD9
8C60B563 80FE367D 8CAD14B3 54FB7A9F
4123FFC4 D63312BA 141AF702 F6BBA254
B094B9C0 FAA4B04C 06CC9AFC FD412671
82E3AEE0 0F0FAAA7 8FA773C9 383A9E18
—— END LICENSE ——
—– BEGIN LICENSE —–
J2TeaM
2 User License
EA7E-940282
45CB0D8F 09100037 7D1056EB A1DDC1A2
39C102C5 DF8D0BF0 FC3B1A94 4F2892B4
0AEE61BA 65758D3B 2EED551F A3E3478C
C1C0E04E CA4E4541 1FC1A2C1 3F5FB6DB
CFDA1551 51B05B5D 2D3C8CFE FA8B4285
051750E3 22D1422A 7AE3A8A1 3B4188AC
346372DA 37AA8ABA 6EB30E41 781BC81F
B5CA66E3 A09DBD3A 3FE85BBD 69893DBD
—— END LICENSE ——

注册码来源

[老法新用]使用padding-top:(percentage)实现响应式背景图片


处理响应式布局中背景图片的简单方法是等比例缩放背景图片。我们知道宽度设为百分比的 <img /> 元素,其高度会随着宽度的变化自动调整,且其宽高比不变。如果想在背景图片中实现同样的效果,我们必须先解决如何保持HTML元素的宽高比。

固定宽高比

我们将用到一个保持元素宽高比的技巧:为元素添加垂直方向的padding值,padding值使用百分比。这是因为垂直方向的padding取值使用百分比时,其值是相对于包含块的宽度而定的 [参考 Box model ]。这个技巧最早在Creating Intrinsic Ratios for Video一文中用来创建固有比率的视频,查看demo

假设我们有一张800*450 px的图片,我们需要创建一个元素在其宽度变化时,它的宽高比仍保持16:9。代码如下:

<div class="column">
    <div class="figure"></div>
</div>
.column{
max-width:800px;}.figure{
padding-top:56.25%;/* 450px/800px = 0.5625 */}

添加背景图片

上面我们实现了元素缩放并保持宽高比。但是此时如果我们添加了背景图片,它并不能跟随元素一起自动缩放。还需要添加background-size:cover。使用这个属性让背景铺满元素的缺点是IE8及以下浏览器不支持,为了使IE下的效果可以接受,可以使用background-position将背景图片居中显式。我们必须要保证图片的宽度至少要与元素的max-width一样大。这样的话元素的宽度永远不会比图片大,如果元素小于图片时,图片将被裁剪。

div.column {/* The background image must be 800px wide */
max-width:800px;}
figure.fixedratio {
padding-top:56.25%;/* 450px/800px = 0.5625 */
background-image: url(http://domain.com/img/sample.jpg);
background-size: cover;
background-position: center;/* Internet Explorer 7/8 */}

流动宽高比

我们可以更深入一步。假设我们有一张在桌面浏览器下显式很好的宽屏图片,在移动设备上我们不想使用相同的宽高比,要不然图片会很小。又或者是我们不想使用相同的高度,因为图片可能会过高。

这个效果可以通过较少padding的百分比值和为元素设置一个高度来实现。假设我们的大图是800*200px,我们打算在元素的宽度减少到300px的时候,背景图片的高度为150px。现在我们计算下heightpadding-top属性值。

上图显式了两个尺寸的关系。坡度线(slop)对应于padding-top属性,开始高度(start height)对应于height属性,它表示元素在宽度为零时的高度。调整样式如下:

div.column {/* The background image must be 800px wide */
max-width:800px;}
figure.fluidratio {
padding-top:10%;/* slope */
height:120px;/* start height */
background-image: url(http://domain.com/img/sample.jpg);
background-size: cover;
background-position: center;/* Internet Explorer 7/8 */}

参考:
Responsive background images with fixed or fluid aspect ratios
Creating Intrinsic Ratios for Video
原文地址:topcss