|
13 | 13 | import org.bouncycastle.crypto.params.SM9SigPrivateKeyParameters; |
14 | 14 | import org.bouncycastle.crypto.params.SM9SigUserKeyParametersGenerator; |
15 | 15 | import org.bouncycastle.crypto.signers.SM9Signer; |
| 16 | +import org.bouncycastle.math.ec.ECPoint; |
| 17 | +import org.bouncycastle.math.ec.sm9.Fp12; |
| 18 | +import org.bouncycastle.math.ec.sm9.SM9Curve; |
| 19 | +import org.bouncycastle.math.ec.sm9.SM9Pairing; |
16 | 20 | import org.bouncycastle.test.TestResourceFinder; |
17 | 21 | import org.bouncycastle.util.Arrays; |
| 22 | +import org.bouncycastle.util.BigIntegers; |
18 | 23 | import org.bouncycastle.util.encoders.Hex; |
19 | 24 | import org.bouncycastle.util.test.SimpleTest; |
20 | 25 | import org.bouncycastle.util.test.TestRandomBigInteger; |
@@ -83,6 +88,12 @@ public void performTest() |
83 | 88 | SM9SigUserKeyParametersGenerator kgc = master; |
84 | 89 | SM9SigPrivateKeyParameters userKey = kgc.generateUserKey(identity); |
85 | 90 |
|
| 91 | + // the domain parameters, generators, derived keys and pairing values the |
| 92 | + // standard prints alongside the signature itself (GM/T 0044.5-2016 Annex A) |
| 93 | + checkDomainParameters(v); |
| 94 | + checkKeyDerivation(v, master, userKey); |
| 95 | + checkPairingValues(v, master); |
| 96 | + |
86 | 97 | SM9Signer signer = new SM9Signer(); |
87 | 98 | signer.init(true, new ParametersWithRandom(userKey, new TestRandomBigInteger(256, hex(v, "r")))); |
88 | 99 | signer.update(msg, 0, msg.length); |
@@ -123,6 +134,70 @@ public void performTest() |
123 | 134 | !emptyWrong.verifySignature(emptySig)); |
124 | 135 | } |
125 | 136 |
|
| 137 | + /** |
| 138 | + * The curve order and the two group generators printed by the standard. |
| 139 | + */ |
| 140 | + private void checkDomainParameters(Map v) |
| 141 | + { |
| 142 | + isTrue("SM9 curve order N", Arrays.areEqual(f32(SM9Curve.N), hex(v, "N"))); |
| 143 | + |
| 144 | + ECPoint p1 = SM9Curve.P1.normalize(); |
| 145 | + isTrue("SM9 generator P1.x", |
| 146 | + Arrays.areEqual(f32(p1.getAffineXCoord().toBigInteger()), hex(v, "P1x"))); |
| 147 | + isTrue("SM9 generator P1.y", |
| 148 | + Arrays.areEqual(f32(p1.getAffineYCoord().toBigInteger()), hex(v, "P1y"))); |
| 149 | + |
| 150 | + // G2 points serialize as 0x04 || x_hi || x_lo || y_hi || y_lo, each F_p2 |
| 151 | + // coordinate high-dimension (u-coefficient) first |
| 152 | + isTrue("SM9 generator P2", Arrays.areEqual(SM9Curve.P2.getEncoded(), |
| 153 | + g2(v, "P2x_hi", "P2x_lo", "P2y_hi", "P2y_lo"))); |
| 154 | + } |
| 155 | + |
| 156 | + /** |
| 157 | + * The KGC derivation chain: the signature master public key P_pub-s = [ks]P2 |
| 158 | + * and the user's signing key ds_A = [t2]P1. |
| 159 | + */ |
| 160 | + private void checkKeyDerivation(Map v, SM9SigMasterPrivateKeyParameters master, |
| 161 | + SM9SigPrivateKeyParameters userKey) |
| 162 | + { |
| 163 | + isTrue("SM9 master public key Ppub-s", Arrays.areEqual( |
| 164 | + master.getPublicKeyParameters().getEncoded(), |
| 165 | + g2(v, "Ppubsx_hi", "Ppubsx_lo", "Ppubsy_hi", "Ppubsy_lo"))); |
| 166 | + |
| 167 | + ECPoint ds = userKey.getPrivatePoint().normalize(); |
| 168 | + isTrue("SM9 user signing key dsA.x", |
| 169 | + Arrays.areEqual(f32(ds.getAffineXCoord().toBigInteger()), hex(v, "dsAx"))); |
| 170 | + isTrue("SM9 user signing key dsA.y", |
| 171 | + Arrays.areEqual(f32(ds.getAffineYCoord().toBigInteger()), hex(v, "dsAy"))); |
| 172 | + } |
| 173 | + |
| 174 | + /** |
| 175 | + * The R-ate pairing itself, against the two G_T values the standard prints: |
| 176 | + * g = e(P1, P_pub-s) and w = g^r. Without these the pairing is only checked |
| 177 | + * indirectly, through the signature components. |
| 178 | + */ |
| 179 | + private void checkPairingValues(Map v, SM9SigMasterPrivateKeyParameters master) |
| 180 | + { |
| 181 | + Fp12 g = SM9Pairing.pairing(SM9Curve.P1, master.getPublicKeyParameters().getPointG2()); |
| 182 | + isTrue("SM9 pairing g = e(P1, Ppub-s)", |
| 183 | + Arrays.areEqual(SM9Pairing.toBytes(g), hex(v, "g_GT"))); |
| 184 | + |
| 185 | + Fp12 w = g.pow(new BigInteger((String)v.get("r"), 16)); |
| 186 | + isTrue("SM9 pairing w = g^r", Arrays.areEqual(SM9Pairing.toBytes(w), hex(v, "w_GT"))); |
| 187 | + } |
| 188 | + |
| 189 | + private byte[] g2(Map v, String xHi, String xLo, String yHi, String yLo) |
| 190 | + { |
| 191 | + return Arrays.concatenate( |
| 192 | + Arrays.concatenate(new byte[]{0x04}, hex(v, xHi), hex(v, xLo)), |
| 193 | + Arrays.concatenate(hex(v, yHi), hex(v, yLo))); |
| 194 | + } |
| 195 | + |
| 196 | + private static byte[] f32(BigInteger v) |
| 197 | + { |
| 198 | + return BigIntegers.asUnsignedByteArray(32, v); |
| 199 | + } |
| 200 | + |
126 | 201 | public static void main(String[] args) |
127 | 202 | { |
128 | 203 | runTest(new SM9SignerTest()); |
|
0 commit comments