Class: BLS::PointG2
- Inherits:
-
ProjectivePoint
- Object
- ProjectivePoint
- BLS::PointG2
- Defined in:
- lib/bls/point/g2.rb
Constant Summary collapse
- DST_BASIC =
Ciphersuite IDs of draft-irtf-cfrg-bls-signature section 4.2.
'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_'- DST_POP =
'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_'- DST_POP_PROOF =
'BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_'- KEY_SIZE_COMPRESSED =
96- KEY_SIZE_UNCOMPRESSED =
192- MAX_BITS =
Fp2::MAX_BITS
- BASE =
PointG2.new(Fp2.new(Curve::G2_X), Fp2.new(Curve::G2_Y), Fp2::ONE)
- ZERO =
PointG2.new(Fp2::ONE, Fp2::ONE, Fp2::ZERO)
Instance Attribute Summary collapse
-
#precomputes ⇒ Object
Returns the value of attribute precomputes.
Class Method Summary collapse
- .clear_cofactor(p) ⇒ Object
-
.from_hex(hex) ⇒ BLS::PointG2
Parse PointG2 from form hex.
-
.from_private_key(private_key) ⇒ PointG1
Parse Point from private key.
-
.hash_to_curve(message, scheme: :basic, dst: nil) ⇒ BLS::PointG2
Convert hash to PointG2 ciphersuite this library does not name, such as the ones the RFC 9380 vectors use.
Instance Method Summary collapse
- #clear_pairing_precomputes ⇒ Object
-
#pairing_precomputes ⇒ Array
The line coefficients miller_loop needs, worked out once and kept on the point.
-
#to_hex(compressed: false) ⇒ String
Serialize pont as hex value.
-
#to_signature ⇒ String
deprecated
Deprecated.
Use #to_hex instead.
- #validate! ⇒ Object
Instance Attribute Details
#precomputes ⇒ Object
Returns the value of attribute precomputes.
4 5 6 |
# File 'lib/bls/point/g2.rb', line 4 def precomputes @precomputes end |
Class Method Details
.clear_cofactor(p) ⇒ Object
203 204 205 206 207 208 |
# File 'lib/bls/point/g2.rb', line 203 def self.clear_cofactor(p) t1 = p.multiply_unsafe(Curve::X).negate t2 = p.from_affine_tuple(BLS.psi(*p.to_affine)) p2 = p.from_affine_tuple(BLS.psi2(*p.double.to_affine)) p2 - t2 + (t1 + t2).multiply_unsafe(Curve::X).negate - t1 - p end |
.from_hex(hex) ⇒ BLS::PointG2
Parse PointG2 from form hex. https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-07#section-appendix.c
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/bls/point/g2.rb', line 23 def self.from_hex(hex) validate_hex!(hex) bytes = [hex].pack('H*') unless [KEY_SIZE_COMPRESSED, KEY_SIZE_UNCOMPRESSED].include?(bytes.bytesize) raise PointError, 'Invalid point G2, expected 96/192 bytes.' end m_byte = bytes[0].unpack1('C')& 0xe0 if [0x20, 0x60, 0xe0].include?(m_byte) raise PointError, "Invalid encoding flag: #{m_byte.to_s(16)}" end c_bit = m_byte & POINT_COMPRESSION_FLAG # compression flag i_bit = m_byte & POINT_INFINITY_FLAG # infinity flag s_bit = m_byte & POINT_Y_FLAG # y coordinate sign flag bytes[0] = [bytes[0].unpack1('C') & 0x1f].pack('C') # set flag to 0 if i_bit == POINT_INFINITY_FLAG && bytes.unpack1('H*').to_i(16) > 0 raise PointError, 'Invalid point, infinity point should be all 0.' end point = if bytes.bytesize == KEY_SIZE_COMPRESSED && c_bit == POINT_COMPRESSION_FLAG # compress format return ZERO if i_bit == POINT_INFINITY_FLAG x1 = bytes[0...PUBLIC_KEY_LENGTH].unpack1('H*').to_i(16) x0 = bytes[PUBLIC_KEY_LENGTH...(2 * PUBLIC_KEY_LENGTH)].unpack1('H*').to_i(16) x = Fp2.new([x0, x1]) right = x ** 3 + Fp2.new(Curve::B2) y = right.sqrt raise PointError, 'Invalid compressed G2 point' unless y bit_y = if y.coeffs[1].value == 0 (y.coeffs[0].value * 2) / Curve::P else (y.coeffs[1].value * 2) / Curve::P == 1 ? 1 : 0 end # Flip to whichever root the encoding asked for. Written as a comparison, the # way G1 does it, rather than as `s_bit > 0 && bit_y > 0 ? y : y.negate`: # that form is only right because sqrt returns the root of sign 1, which it # does not promise, and it would negate a root of sign 0 that wanted sign 0. y = y.negate unless bit_y == (s_bit.zero? ? 0 : 1) PointG2.new(x, y, Fp2::ONE) elsif bytes.bytesize == KEY_SIZE_UNCOMPRESSED && c_bit != POINT_COMPRESSION_FLAG # uncompressed format return ZERO if i_bit == POINT_INFINITY_FLAG x1 = bytes[0...PUBLIC_KEY_LENGTH].unpack1('H*').to_i(16) x0 = bytes[PUBLIC_KEY_LENGTH...(2 * PUBLIC_KEY_LENGTH)].unpack1('H*').to_i(16) y1 = bytes[(2 * PUBLIC_KEY_LENGTH)...(3 * PUBLIC_KEY_LENGTH)].unpack1('H*').to_i(16) y0 = bytes[(3 * PUBLIC_KEY_LENGTH)..-1].unpack1('H*').to_i(16) PointG2.new(Fp2.new([x0, x1]), Fp2.new([y0, y1]), Fp2::ONE) else raise PointError, 'Invalid point G2, compression flag does not match the encoded length.' end point.validate! point.validate_group! point end |
.from_private_key(private_key) ⇒ PointG1
Parse Point from private key.
82 83 84 |
# File 'lib/bls/point/g2.rb', line 82 def self.from_private_key(private_key) BASE * BLS.normalize_priv_key(private_key) end |
.hash_to_curve(message, scheme: :basic, dst: nil) ⇒ BLS::PointG2
Convert hash to PointG2 ciphersuite this library does not name, such as the ones the RFC 9380 vectors use.
93 94 95 96 97 98 99 100 101 |
# File 'lib/bls/point/g2.rb', line 93 def self.hash_to_curve(, scheme: :basic, dst: nil) validate_hex!() u = BLS::H2C::G2.hash_to_field(, dst || self.dst(scheme)) q0 = PointG2.new(*BLS::H2C::G2.isogeny_map(*BLS::H2C::G2.map_to_curve_sswu(u[0]))) q1 = PointG2.new(*BLS::H2C::G2.isogeny_map(*BLS::H2C::G2.map_to_curve_sswu(u[1]))) r = q0 + q1 clear_cofactor(r) end |
Instance Method Details
#clear_pairing_precomputes ⇒ Object
152 153 154 |
# File 'lib/bls/point/g2.rb', line 152 def clear_pairing_precomputes self.precomputes = nil end |
#pairing_precomputes ⇒ Array
The line coefficients BLS.miller_loop needs, worked out once and kept on the point.
This memoises without a lock, so concurrent callers can each compute it. They compute the same coefficients and assign a finished array, so a reader sees one or the other and never a partial one; the cost is the repeated work. BLS.verify reaches this on PointG2::BASE, which is shared, whenever the public key is a G2 point.
163 164 165 166 167 168 |
# File 'lib/bls/point/g2.rb', line 163 def pairing_precomputes return precomputes if precomputes self.precomputes = calc_pairing_precomputes(*to_affine) precomputes end |
#to_hex(compressed: false) ⇒ String
Serialize pont as hex value.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/bls/point/g2.rb', line 106 def to_hex(compressed: false) if compressed if zero? x1 = POW_2_383 + POW_2_382 x0= 0 else x, y = to_affine flag = if y.coeffs[1].value == 0 (y.coeffs[0].value * 2) / Curve::P else ((y.coeffs[1].value * 2) / Curve::P).zero? ? 0 : 1 end x1 = x.coeffs[1].value + flag * POW_2_381 + POW_2_383 x0 = x.coeffs[0].value end BLS.num_to_hex(x1, PUBLIC_KEY_LENGTH) + BLS.num_to_hex(x0, PUBLIC_KEY_LENGTH) else if self == PointG2::ZERO (1 << 6).to_s(16) + '00' * (4 * PUBLIC_KEY_LENGTH - 1) else validate! x, y = to_affine.map(&:values) BLS.num_to_hex(x[1], PUBLIC_KEY_LENGTH) + BLS.num_to_hex(x[0], PUBLIC_KEY_LENGTH) + BLS.num_to_hex(y[1], PUBLIC_KEY_LENGTH) + BLS.num_to_hex(y[0], PUBLIC_KEY_LENGTH) end end end |
#to_signature ⇒ String
Use #to_hex instead.
Convert to signature with hex format.
139 140 141 |
# File 'lib/bls/point/g2.rb', line 139 def to_signature to_hex(compressed: true) end |
#validate! ⇒ Object
143 144 145 146 147 148 149 150 |
# File 'lib/bls/point/g2.rb', line 143 def validate! b = Fp2.new(Curve::B2) return if zero? left = y.pow(2) * z - x.pow(3) right = b * z.pow(3) raise PointError, 'Invalid point: not on curve over Fp2' unless left == right end |