// Copyright 2012 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package elliptic// This is a constant-time, 32-bit implementation of P224. See FIPS 186-3,// section D.2.2.//// See https://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.import ()varp224p224Curvetypep224Curvestruct { *CurveParams gx, gy, b p224FieldElement}func () {// See FIPS 186-3, section D.2.2p224.CurveParams = &CurveParams{Name: "P-224"}p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)p224.BitSize = 224p224FromBig(&p224.gx, p224.Gx)p224FromBig(&p224.gy, p224.Gy)p224FromBig(&p224.b, p224.B)}// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2).//// The cryptographic operations are implemented using constant-time algorithms.func () Curve {initonce.Do(initAll)returnp224}func ( p224Curve) () *CurveParams {return .CurveParams}func ( p224Curve) (, *big.Int) bool {var , p224FieldElementp224FromBig(&, )p224FromBig(&, )// y² = x³ - 3x + bvarp224LargeFieldElementvarp224FieldElementp224Square(&, &, &)p224Mul(&, &, &, &)for := 0; < 8; ++ { [] *= 3 }p224Sub(&, &, &)p224Reduce(&)p224Add(&, &, &.b)p224Contract(&, &)p224Square(&, &, &)p224Contract(&, &)for := 0; < 8; ++ {if [] != [] {returnfalse } }returntrue}func (p224Curve) (, , , *big.Int) (, *big.Int) {var , , , , , , , , p224FieldElementp224FromBig(&, )p224FromBig(&, )if .Sign() != 0 || .Sign() != 0 { [0] = 1 }p224FromBig(&, )p224FromBig(&, )if .Sign() != 0 || .Sign() != 0 { [0] = 1 }p224AddJacobian(&, &, &, &, &, &, &, &, &)returnp224ToAffine(&, &, &)}func (p224Curve) (, *big.Int) (, *big.Int) {var , , , , , p224FieldElementp224FromBig(&, )p224FromBig(&, ) [0] = 1p224DoubleJacobian(&, &, &, &, &, &)returnp224ToAffine(&, &, &)}func (p224Curve) (, *big.Int, []byte) (, *big.Int) {var , , , , , p224FieldElementp224FromBig(&, )p224FromBig(&, ) [0] = 1p224ScalarMult(&, &, &, &, &, &, )returnp224ToAffine(&, &, &)}func ( p224Curve) ( []byte) (, *big.Int) {var , , , p224FieldElement [0] = 1p224ScalarMult(&, &, &, &.gx, &.gy, &, )returnp224ToAffine(&, &, &)}// Field element functions.//// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1.//// Field elements are represented by a FieldElement, which is a typedef to an// array of 8 uint32's. The value of a FieldElement, a, is:// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7]//// Using 28-bit limbs means that there's only 4 bits of headroom, which is less// than we would really like. But it has the useful feature that we hit 2**224// exactly, making the reflections during a reduce much nicer.typep224FieldElement [8]uint32// p224P is the order of the field, represented as a p224FieldElement.varp224P = [8]uint32{1, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}// p224IsZero returns 1 if a == 0 mod p and 0 otherwise.//// a[i] < 2**29func ( *p224FieldElement) uint32 {// Since a p224FieldElement contains 224 bits there are two possible // representations of 0: 0 and p.varp224FieldElementp224Contract(&, )var , uint32for , := range { |= |= - p224P[] }// If either isZero or isP is 0, then we should return 1. |= >> 16 |= >> 8 |= >> 4 |= >> 2 |= >> 1 |= >> 16 |= >> 8 |= >> 4 |= >> 2 |= >> 1// For isZero and isP, the LSB is 0 iff all the bits are zero. := & = (^) & 1return}// p224Add computes *out = a+b//// a[i] + b[i] < 2**32func (, , *p224FieldElement) {for := 0; < 8; ++ { [] = [] + [] }}consttwo31p3 = 1<<31 + 1<<3consttwo31m3 = 1<<31 - 1<<3consttwo31m15m3 = 1<<31 - 1<<15 - 1<<3// p224ZeroModP31 is 0 mod p where bit 31 is set in all limbs so that we can// subtract smaller amounts without underflow. See the section "Subtraction" in// [1] for reasoning.varp224ZeroModP31 = []uint32{two31p3, two31m3, two31m3, two31m15m3, two31m3, two31m3, two31m3, two31m3}// p224Sub computes *out = a-b//// a[i], b[i] < 2**30// out[i] < 2**32func (, , *p224FieldElement) {for := 0; < 8; ++ { [] = [] + p224ZeroModP31[] - [] }}// LargeFieldElement also represents an element of the field. The limbs are// still spaced 28-bits apart and in little-endian order. So the limbs are at// 0, 28, 56, ..., 392 bits, each 64-bits wide.typep224LargeFieldElement [15]uint64consttwo63p35 = 1<<63 + 1<<35consttwo63m35 = 1<<63 - 1<<35consttwo63m35m19 = 1<<63 - 1<<35 - 1<<19// p224ZeroModP63 is 0 mod p where bit 63 is set in all limbs. See the section// "Subtraction" in [1] for why.varp224ZeroModP63 = [8]uint64{two63p35, two63m35, two63m35, two63m35, two63m35m19, two63m35, two63m35, two63m35}constbottom12Bits = 0xfffconstbottom28Bits = 0xfffffff// p224Mul computes *out = a*b//// a[i] < 2**29, b[i] < 2**30 (or vice versa)// out[i] < 2**29func (, , *p224FieldElement, *p224LargeFieldElement) {for := 0; < 15; ++ { [] = 0 }for := 0; < 8; ++ {for := 0; < 8; ++ { [+] += uint64([]) * uint64([]) } }p224ReduceLarge(, )}// Square computes *out = a*a//// a[i] < 2**29// out[i] < 2**29func (, *p224FieldElement, *p224LargeFieldElement) {for := 0; < 15; ++ { [] = 0 }for := 0; < 8; ++ {for := 0; <= ; ++ { := uint64([]) * uint64([])if == { [+] += } else { [+] += << 1 } } }p224ReduceLarge(, )}// ReduceLarge converts a p224LargeFieldElement to a p224FieldElement.//// in[i] < 2**62func ( *p224FieldElement, *p224LargeFieldElement) {for := 0; < 8; ++ { [] += p224ZeroModP63[] }// Eliminate the coefficients at 2**224 and greater.for := 14; >= 8; -- { [-8] -= [] [-5] += ([] & 0xffff) << 12 [-4] += [] >> 16 } [8] = 0// in[0..8] < 2**64// As the values become small enough, we start to store them in |out| // and use 32-bit operations.for := 1; < 8; ++ { [+1] += [] >> 28 [] = uint32([] & bottom28Bits) } [0] -= [8] [3] += uint32([8]&0xffff) << 12 [4] += uint32([8] >> 16)// in[0] < 2**64 // out[3] < 2**29 // out[4] < 2**29 // out[1,2,5..7] < 2**28 [0] = uint32([0] & bottom28Bits) [1] += uint32(([0] >> 28) & bottom28Bits) [2] += uint32([0] >> 56)// out[0] < 2**28 // out[1..4] < 2**29 // out[5..7] < 2**28}// Reduce reduces the coefficients of a to smaller bounds.//// On entry: a[i] < 2**31 + 2**30// On exit: a[i] < 2**29func ( *p224FieldElement) {for := 0; < 7; ++ { [+1] += [] >> 28 [] &= bottom28Bits } := [7] >> 28 [7] &= bottom28Bits// top < 2**4 := |= >> 2 |= >> 1 <<= 31 = uint32(int32() >> 31)// Mask is all ones if top != 0, all zero otherwise [0] -= [3] += << 12// We may have just made a[0] negative but, if we did, then we must // have added something to a[3], this it's > 2**12. Therefore we can // carry down to a[0]. [3] -= 1 & [2] += & (1<<28 - 1) [1] += & (1<<28 - 1) [0] += & (1 << 28)}// p224Invert calculates *out = in**-1 by computing in**(2**224 - 2**96 - 1),// i.e. Fermat's little theorem.func (, *p224FieldElement) {var , , , p224FieldElementvarp224LargeFieldElementp224Square(&, , &) // 2p224Mul(&, &, , &) // 2**2 - 1p224Square(&, &, &) // 2**3 - 2p224Mul(&, &, , &) // 2**3 - 1p224Square(&, &, &) // 2**4 - 2p224Square(&, &, &) // 2**5 - 4p224Square(&, &, &) // 2**6 - 8p224Mul(&, &, &, &) // 2**6 - 1p224Square(&, &, &) // 2**7 - 2for := 0; < 5; ++ { // 2**12 - 2**6p224Square(&, &, &) }p224Mul(&, &, &, &) // 2**12 - 1p224Square(&, &, &) // 2**13 - 2for := 0; < 11; ++ { // 2**24 - 2**12p224Square(&, &, &) }p224Mul(&, &, &, &) // 2**24 - 1p224Square(&, &, &) // 2**25 - 2for := 0; < 23; ++ { // 2**48 - 2**24p224Square(&, &, &) }p224Mul(&, &, &, &) // 2**48 - 1p224Square(&, &, &) // 2**49 - 2for := 0; < 47; ++ { // 2**96 - 2**48p224Square(&, &, &) }p224Mul(&, &, &, &) // 2**96 - 1p224Square(&, &, &) // 2**97 - 2for := 0; < 23; ++ { // 2**120 - 2**24p224Square(&, &, &) }p224Mul(&, &, &, &) // 2**120 - 1for := 0; < 6; ++ { // 2**126 - 2**6p224Square(&, &, &) }p224Mul(&, &, &, &) // 2**126 - 1p224Square(&, &, &) // 2**127 - 2p224Mul(&, &, , &) // 2**127 - 1for := 0; < 97; ++ { // 2**224 - 2**97p224Square(&, &, &) }p224Mul(, &, &, &) // 2**224 - 2**96 - 1}// p224Contract converts a FieldElement to its unique, minimal form.//// On entry, in[i] < 2**29// On exit, out[i] < 2**28 and out < pfunc (, *p224FieldElement) {copy([:], [:])// First, carry the bits above 28 to the higher limb.for := 0; < 7; ++ { [+1] += [] >> 28 [] &= bottom28Bits } := [7] >> 28 [7] &= bottom28Bits// Use the reduction identity to carry the overflow. // // a + top * 2²²⁴ = a + top * 2⁹⁶ - top [0] -= [3] += << 12// We may just have made out[0] negative. So we carry down. If we made // out[0] negative then we know that out[3] is sufficiently positive // because we just added to it.for := 0; < 3; ++ { := uint32(int32([]) >> 31) [] += (1 << 28) & [+1] -= 1 & }// We might have pushed out[3] over 2**28 so we perform another, partial, // carry chain.for := 3; < 7; ++ { [+1] += [] >> 28 [] &= bottom28Bits } = [7] >> 28 [7] &= bottom28Bits// Eliminate top while maintaining the same value mod p. [0] -= [3] += << 12// There are two cases to consider for out[3]: // 1) The first time that we eliminated top, we didn't push out[3] over // 2**28. In this case, the partial carry chain didn't change any values // and top is now zero. // 2) We did push out[3] over 2**28 the first time that we eliminated top. // The first value of top was in [0..2], therefore, after overflowing // and being reduced by the second carry chain, out[3] <= 2<<12 - 1. // In both cases, out[3] cannot have overflowed when we eliminated top for // the second time.// Again, we may just have made out[0] negative, so do the same carry down. // As before, if we made out[0] negative then we know that out[3] is // sufficiently positive.for := 0; < 3; ++ { := uint32(int32([]) >> 31) [] += (1 << 28) & [+1] -= 1 & }// Now we see if the value is >= p and, if so, subtract p.// First we build a mask from the top four limbs, which must all be // equal to bottom28Bits if the whole value is >= p. If top4AllOnes // ends up with any zero bits in the bottom 28 bits, then this wasn't // true. := uint32(0xffffffff)for := 4; < 8; ++ { &= [] } |= 0xf0000000// Now we replicate any zero bits to all the bits in top4AllOnes. &= >> 16 &= >> 8 &= >> 4 &= >> 2 &= >> 1 = uint32(int32(<<31) >> 31)// Now we test whether the bottom three limbs are non-zero. := [0] | [1] | [2] |= >> 16 |= >> 8 |= >> 4 |= >> 2 |= >> 1 = uint32(int32(<<31) >> 31)// Assuming top4AllOnes != 0, everything depends on the value of out[3]. // If it's > 0xffff000 then the whole value is > p // If it's = 0xffff000 and bottom3NonZero != 0, then the whole value is >= p // If it's < 0xffff000, then the whole value is < p := 0xffff000 - [3] := |= >> 16 |= >> 8 |= >> 4 |= >> 2 |= >> 1 = ^uint32(int32(<<31) >> 31)// If out[3] > 0xffff000 then n's MSB will be one. := uint32(int32() >> 31) := & (( & ) | ) [0] -= 1 & [3] -= 0xffff000 & [4] -= 0xfffffff & [5] -= 0xfffffff & [6] -= 0xfffffff & [7] -= 0xfffffff & // Do one final carry down, in case we made out[0] negative. One of // out[0..3] needs to be positive and able to absorb the -1 or the value // would have been < p, and the subtraction wouldn't have happened.for := 0; < 3; ++ { := uint32(int32([]) >> 31) [] += (1 << 28) & [+1] -= 1 & }}// Group element functions.//// These functions deal with group elements. The group is an elliptic curve// group with a = -3 defined in FIPS 186-3, section D.2.2.// p224AddJacobian computes *out = a+b where a != b.func (, , , , , , , , *p224FieldElement) {// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-p224Add-2007-blvar , , , , , , , , , , p224FieldElementvarp224LargeFieldElement := p224IsZero() := p224IsZero()// Z1Z1 = Z1²p224Square(&, , &)// Z2Z2 = Z2²p224Square(&, , &)// U1 = X1*Z2Z2p224Mul(&, , &, &)// U2 = X2*Z1Z1p224Mul(&, , &, &)// S1 = Y1*Z2*Z2Z2p224Mul(&, , &, &)p224Mul(&, , &, &)// S2 = Y2*Z1*Z1Z1p224Mul(&, , &, &)p224Mul(&, , &, &)// H = U2-U1p224Sub(&, &, &)p224Reduce(&) := p224IsZero(&)// I = (2*H)²for := 0; < 8; ++ { [] = [] << 1 }p224Reduce(&)p224Square(&, &, &)// J = H*Ip224Mul(&, &, &, &)// r = 2*(S2-S1)p224Sub(&, &, &)p224Reduce(&) := p224IsZero(&)if == 1 && == 1 && == 0 && == 0 {p224DoubleJacobian(, , , , , )return }for := 0; < 8; ++ { [] <<= 1 }p224Reduce(&)// V = U1*Ip224Mul(&, &, &, &)// Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*Hp224Add(&, &, &)p224Add(&, , )p224Reduce(&)p224Square(&, &, &)p224Sub(, &, &)p224Reduce()p224Mul(, , &, &)// X3 = r²-J-2*Vfor := 0; < 8; ++ { [] = [] << 1 }p224Add(&, &, &)p224Reduce(&)p224Square(, &, &)p224Sub(, , &)p224Reduce()// Y3 = r*(V-X3)-2*S1*Jfor := 0; < 8; ++ { [] <<= 1 }p224Mul(&, &, &, &)p224Sub(&, &, )p224Reduce(&)p224Mul(&, &, &, &)p224Sub(, &, &)p224Reduce()p224CopyConditional(, , )p224CopyConditional(, , )p224CopyConditional(, , )p224CopyConditional(, , )p224CopyConditional(, , )p224CopyConditional(, , )}// p224DoubleJacobian computes *out = a+a.func (, , , , , *p224FieldElement) {var , , , , p224FieldElementvarp224LargeFieldElementp224Square(&, , &)p224Square(&, , &)p224Mul(&, , &, &)// alpha = 3*(X1-delta)*(X1+delta)p224Add(&, , &)for := 0; < 8; ++ { [] += [] << 1 }p224Reduce(&)p224Sub(&, , &)p224Reduce(&)p224Mul(&, &, &, &)// Z3 = (Y1+Z1)²-gamma-deltap224Add(, , )p224Reduce()p224Square(, , &)p224Sub(, , &)p224Reduce()p224Sub(, , &)p224Reduce()// X3 = alpha²-8*betafor := 0; < 8; ++ { [] = [] << 3 }p224Reduce(&)p224Square(, &, &)p224Sub(, , &)p224Reduce()// Y3 = alpha*(4*beta-X3)-8*gamma²for := 0; < 8; ++ { [] <<= 2 }p224Sub(&, &, )p224Reduce(&)p224Square(&, &, &)for := 0; < 8; ++ { [] <<= 3 }p224Reduce(&)p224Mul(, &, &, &)p224Sub(, , &)p224Reduce()}// p224CopyConditional sets *out = *in iff the least-significant-bit of control// is true, and it runs in constant time.func (, *p224FieldElement, uint32) { <<= 31 = uint32(int32() >> 31)for := 0; < 8; ++ { [] ^= ([] ^ []) & }}func (, , , , , *p224FieldElement, []byte) {var , , p224FieldElementfor := 0; < 8; ++ { [] = 0 [] = 0 [] = 0 }for , := range {for := uint(0); < 8; ++ {p224DoubleJacobian(, , , , , ) := uint32(( >> (7 - )) & 1)p224AddJacobian(&, &, &, , , , , , )p224CopyConditional(, &, )p224CopyConditional(, &, )p224CopyConditional(, &, ) } }}// p224ToAffine converts from Jacobian to affine form.func (, , *p224FieldElement) (*big.Int, *big.Int) {var , , , p224FieldElementvarp224LargeFieldElementif := p224IsZero(); == 1 {returnnew(big.Int), new(big.Int) }p224Invert(&, )p224Square(&, &, &)p224Mul(, , &, &)p224Mul(&, &, &, &)p224Mul(, , &, &)p224Contract(&, )p224Contract(&, )returnp224ToBig(&), p224ToBig(&)}// get28BitsFromEnd returns the least-significant 28 bits from buf>>shift,// where buf is interpreted as a big-endian number.func ( []byte, uint) (uint32, []byte) {varuint32for := uint(0); < 4; ++ {varbyteif := len(); > 0 { = [-1]// We don't remove the byte if we're about to return and we're not // reading all of it.if != 3 || == 4 { = [:-1] } } |= uint32() << (8 * ) >> } &= bottom28Bitsreturn , }// p224FromBig sets *out = *in.func ( *p224FieldElement, *big.Int) { := .Bytes() [0], = get28BitsFromEnd(, 0) [1], = get28BitsFromEnd(, 4) [2], = get28BitsFromEnd(, 0) [3], = get28BitsFromEnd(, 4) [4], = get28BitsFromEnd(, 0) [5], = get28BitsFromEnd(, 4) [6], = get28BitsFromEnd(, 0) [7], = get28BitsFromEnd(, 4)}// p224ToBig returns in as a big.Int.func ( *p224FieldElement) *big.Int {var [28]byte [27] = byte([0]) [26] = byte([0] >> 8) [25] = byte([0] >> 16) [24] = byte((([0] >> 24) & 0x0f) | ([1]<<4)&0xf0) [23] = byte([1] >> 4) [22] = byte([1] >> 12) [21] = byte([1] >> 20) [20] = byte([2]) [19] = byte([2] >> 8) [18] = byte([2] >> 16) [17] = byte((([2] >> 24) & 0x0f) | ([3]<<4)&0xf0) [16] = byte([3] >> 4) [15] = byte([3] >> 12) [14] = byte([3] >> 20) [13] = byte([4]) [12] = byte([4] >> 8) [11] = byte([4] >> 16) [10] = byte((([4] >> 24) & 0x0f) | ([5]<<4)&0xf0) [9] = byte([5] >> 4) [8] = byte([5] >> 12) [7] = byte([5] >> 20) [6] = byte([6]) [5] = byte([6] >> 8) [4] = byte([6] >> 16) [3] = byte((([6] >> 24) & 0x0f) | ([7]<<4)&0xf0) [2] = byte([7] >> 4) [1] = byte([7] >> 12) [0] = byte([7] >> 20)returnnew(big.Int).SetBytes([:])}
The pages are generated with Goldsv0.3.6. (GOOS=darwin GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.