/// Derive an extended key from an extended key public ExtendedKey Derive(Secp256K1 secp, uint n) { var nBytes = BitConverter.GetBytes(n); if (BitConverter.IsLittleEndian) { Array.Reverse(nBytes); } var seed = ByteUtil.Combine(Key.Value, nBytes); var blake2B = new HMACBlake2B(Chaincode, 64 * 8); var derived = blake2B.ComputeHash(seed); var secretKey = SecretKey.From_slice(secp, derived.Take(32).ToArray()); secretKey.Add_assign(secp, Key); // TODO check if key != 0 ? var chainCode = derived.Skip(32).Take(32).ToArray(); return(new ExtendedKey { Depth = (byte)(Depth + 1), RootKeyId = Identifier(secp), NChild = n, Chaincode = chainCode, Key = secretKey }); }
public static ExtendedKey from_slice(Secp256K1 secp, byte[] slice) { // TODO change when ser. ext. size is fixed if (slice.Length != 79) { throw new Exception("InvalidSliceSize"); } var ext = new ExtendedKey { Depth = slice[0] }; var rootKeyBytes = slice.Skip(1).Take(10).ToArray(); ext.RootKeyId = ExtKey.Identifier.From_bytes(rootKeyBytes); var nchildBytes = slice.Skip(11).Take(4).ToArray(); Array.Reverse(nchildBytes); ext.NChild = BitConverter.ToUInt32(nchildBytes, 0); ext.Chaincode = slice.Skip(15).Take(32).ToArray(); var keyBytes = slice.Skip(47).Take(32).ToArray(); ext.Key = SecretKey.From_slice(secp, keyBytes); return(ext); }
public void Invalid_secret_key() { var s = Secp256K1.New(); // Zero var ex = Assert.Throws <Exception>(() => { SecretKey.From_slice(s, ByteUtil.Get_bytes(0, 32)); }); Assert.Equal("InvalidSecretKey", ex.Message); // -1 ex = Assert.Throws <Exception>(() => { SecretKey.From_slice(s, ByteUtil.Get_bytes(0xff, 32)); }); Assert.Equal("InvalidSecretKey", ex.Message); // Top of range var sk1 = SecretKey.From_slice(s, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40 }); Assert.NotEmpty(sk1.Value); // One past top of range Assert.Throws <Exception>(() => { SecretKey.From_slice(s, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }); }); }
public void Sign() { var s = Secp256K1.New(); s.Randomize(RandomNumberGenerator.Create()); var one = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; var sk = SecretKey.From_slice(s, one); var msg = Message.from_slice(one); var sig = s.sign_recoverable(msg, sk); var rsig = RecoverableSigniture.From_compact(s, new byte[] { 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, 0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98, 0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, 0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89 }, RecoveryId.from_i32(1)); Assert.Equal(sig.Value, rsig.Value); }
/// Computes the sum of multiple positive and negative blinding factors. public static SecretKey blind_sum(this Secp256K1 self, SecretKey[] positive, SecretKey[] negative) { //var neg = new byte[negative.Length][]; var all = new byte[positive.Length + negative.Length][]; for (var i = 0; i < positive.Length; i++) { all[i] = positive[i].Value; } for (var i = 0; i < negative.Length; i++) { all[positive.Length + i] = negative[i].Value; } var ret = new byte[32]; var err = Proxy.secp256k1_pedersen_blind_sum( self.Ctx, ret, all, all.Length, positive.Length); if (err == 1) { return(SecretKey.From_slice(self, ret)); } // secp256k1 should never return an invalid private throw new Exception("This should never happen!"); }
public void Extkey_derivation() { // TODO More test vectors var s = Secp256K1.New(); var seed = HexUtil.from_hex("000102030405060708090a0b0c0d0e0f"); var extk = ExtendedKey.from_seed(s, seed); var derived = extk.Derive(s, 0); var sec = HexUtil.from_hex("d75f70beb2bd3b56f9b064087934bdedee98e4b5aae6280c58b4eff38847888f" ); var secretKey = SecretKey.From_slice(s, sec); var chaincode = HexUtil.from_hex("243cb881e1549e714db31d23af45540b13ad07941f64a786bbf3313b4de1df52"); var rootKeyId = HexUtil.from_hex("83e59c48297b78b34b73"); var identifier = HexUtil.from_hex("0185adb4d8b730099c93"); const int depth = 1; const uint nChild = 0; Assert.Equal(derived.Key.Value, secretKey.Value); Assert.Equal( derived.Identifier(s).Value, Identifier.From_bytes(identifier).Value ); Assert.Equal( derived.RootKeyId.Value, Identifier.From_bytes(rootKeyId).Value ); Assert.Equal(derived.Chaincode, chaincode); Assert.Equal(derived.Depth, depth); Assert.Equal(derived.NChild, nChild); }
// For tests and burn only, associate a key identifier with a known secret key. // public static Keychain Burn_enabled(Keychain keychain, Identifier burnKeyId) { var keyOverridesNew = new Dictionary <string, SecretKey> { { burnKeyId.HexValue, SecretKey.From_slice(keychain.Secp, new byte[32]) } }; return(new Keychain(keychain.Secp, keychain.Extkey.Clone(), keyOverridesNew, keychain.KeyDerivationCache)); }
public void Keypair_slice_round_trip() { var secp256K1 = Secp256K1.New(); // ReSharper disable once JoinDeclarationAndInitializer SecretKey sk; var ex = Assert.Throws <Exception>( () => { sk = SecretKey.From_slice(secp256K1, ByteUtil.Get_bytes(1, 31)); }); Assert.Equal("InvalidSecretKey", ex.Message); sk = SecretKey.From_slice(secp256K1, ByteUtil.Get_bytes(1, 32)); Assert.NotEmpty(sk.Value); }
/// Creates a new extended master key from a seed public static ExtendedKey from_seed(Secp256K1 secp, byte[] seed) { switch (seed.Length) { case 16: case 32: case 64: break; default: throw new Exception("InvalidSeedSize"); } var keyData = Encoding.ASCII.GetBytes("Mimble seed"); var blake2B = new HMACBlake2B(keyData, 512); var derived = blake2B.ComputeHash(seed); var chaincode = derived.Skip(32).ToArray(); var secretKeyBytes = derived.Take(32).ToArray(); var secretKey = SecretKey.From_slice(secp, secretKeyBytes); var ext = new ExtendedKey { Depth = 0, RootKeyId = ExtKey.Identifier.Zero(), NChild = 0, Chaincode = chaincode, Key = secretKey, }; ext.RootKeyId = ext.Identifier(secp); return(ext); }
public void Extkey_from_seed() { // TODO More test vectors var s = Secp256K1.New(); var seed = HexUtil.from_hex("000102030405060708090a0b0c0d0e0f"); var extk = ExtendedKey.from_seed(s, seed); var sec = HexUtil.from_hex("c3f5ae520f474b390a637de4669c84d0ed9bbc21742577fac930834d3c3083dd"); var secretKey = SecretKey.From_slice(s, sec); var chaincode = HexUtil.from_hex("e7298e68452b0c6d54837670896e1aee76b118075150d90d4ee416ece106ae72"); var identifier = HexUtil.from_hex("83e59c48297b78b34b73"); const int depth = 0; const uint nChild = 0; Assert.Equal(extk.Key.Value, secretKey.Value); Assert.Equal(extk.Identifier(s).Value, Identifier.From_bytes(identifier).Value); Assert.Equal(extk.RootKeyId.Value, Identifier.From_bytes(identifier).Value); Assert.Equal(extk.Chaincode, chaincode); Assert.Equal(extk.Depth, depth); Assert.Equal(extk.NChild, nChild); }
public void Capabilities() { var none = Secp256K1.WithCaps(ContextFlag.None); var sign = Secp256K1.WithCaps(ContextFlag.SignOnly); var vrfy = Secp256K1.WithCaps(ContextFlag.VerifyOnly); var full = Secp256K1.WithCaps(ContextFlag.Full); var msgBytes = ByteUtil.Get_bytes(0, 32); var msg = Message.from_slice(msgBytes); var rng = RandomNumberGenerator.Create(); // Try key generation var ex = Assert.Throws <Exception>(() => { none.generate_keypair(rng); }); Assert.Equal("IncapableContext", ex.Message); ex = Assert.Throws <Exception>(() => { vrfy.generate_keypair(rng); }); Assert.Equal("IncapableContext", ex.Message); sign.generate_keypair(rng); var fullKp = full.generate_keypair(rng); var sk = fullKp.secretKey; var pk = fullKp.publicKey; // Try signing ex = Assert.Throws <Exception>(() => { none.Sign(msg, sk); }); Assert.Equal("IncapableContext", ex.Message); ex = Assert.Throws <Exception>(() => { vrfy.Sign(msg, sk); }); Assert.Equal("IncapableContext", ex.Message); var ss = sign.Sign(msg, sk); var fs = full.Sign(msg, sk); Assert.Equal(ss.Value, fs.Value); ex = Assert.Throws <Exception>(() => { none.sign_recoverable(msg, sk); }); Assert.Equal("IncapableContext", ex.Message); ex = Assert.Throws <Exception>(() => { vrfy.sign_recoverable(msg, sk); }); Assert.Equal("IncapableContext", ex.Message); var srs = sign.sign_recoverable(msg, sk); var fsr = full.sign_recoverable(msg, sk); Assert.Equal(srs.Value, fsr.Value); var sig = full.Sign(msg, sk); var sigr = full.sign_recoverable(msg, sk); // Try verifying ex = Assert.Throws <Exception>(() => { none.Verify(msg, sig, pk); }); Assert.Equal("IncapableContext", ex.Message); ex = Assert.Throws <Exception>(() => { sign.Verify(msg, sig, pk); }); Assert.Equal("IncapableContext", ex.Message); vrfy.Verify(msg, sig, pk); full.Verify(msg, sig, pk); // Try pk recovery ex = Assert.Throws <Exception>(() => { none.Recover(msg, sigr); }); Assert.Equal("IncapableContext", ex.Message); ex = Assert.Throws <Exception>(() => { sign.Recover(msg, sigr); }); Assert.Equal("IncapableContext", ex.Message); var vrc = vrfy.Recover(msg, sigr); var frc = full.Recover(msg, sigr); Assert.Equal(vrc.Value, frc.Value); Assert.Equal(frc.Value, pk.Value); // Check that we can produce keys from slices with no precomputation var pkSlice = pk.serialize_vec(none, false); var skSlice = sk.Value; var newPk = PublicKey.from_slice(none, pkSlice); var newSk = SecretKey.From_slice(none, skSlice); Assert.Equal(sk.Value, newSk.Value); Assert.Equal(pk.Value, newPk.Value); none.Dispose(); sign.Dispose(); vrfy.Dispose(); full.Dispose(); }
public static BlindingFactor from_slice(Secp256K1 secp, byte[] data) { return(new BlindingFactor(SecretKey.From_slice(secp, data))); }