public static RangeProof range_proof(this Secp256K1 self, ulong min, ulong value, SecretKey blind, Commitment commit, ProofMessage message) { var retried = false; var proof = new byte[Constants.Constants.MaxProofSize]; var plen = Constants.Constants.MaxProofSize; // IntPtr proofPtr= Marshal.AllocHGlobal(proof.Length); var proofPtr = Marshal.AllocCoTaskMem(plen); Marshal.Copy(proof, 0, proofPtr, proof.Length); // Marshal.Copy(proof, 0, proofPtr, proof.Length); // use a "known key" as the nonce, specifically the blinding factor // of the commitment for which we are generating the range proof // so we can later recover the value and the message by unwinding the range proof // with the same nonce var nonce = blind.Clone(); var extraCommit = ByteUtil.Get_bytes(0, 33); // TODO - confirm this reworked retry logic works as expected // pretty sure the original approach retried on success (so twice in total) // and just kept looping forever on error do { var success = Proxy.secp256k1_rangeproof_sign( self.Ctx, proofPtr, ref plen, min, commit.Value, blind.Value, nonce.Value, 0, 64, value, message.Value, message.Value.Length, extraCommit, 0, Constants.Constants.GeneratorH) == 1; if (success || retried) { break; } retried = true; } while (true); var proof2 = new byte[plen]; Marshal.Copy(proofPtr, proof2, 0, plen); Marshal.FreeCoTaskMem(proofPtr); return(new RangeProof(proof2, plen)); }
/// *** This is a temporary work-around. *** /// We do not know which of the two possible public keys from the commit to use, /// so here we try both of them and succeed if either works. /// This is sub-optimal in terms of performance. /// I believe apoelstra has a strategy for fixing this in the secp256k1-zkp lib. public static void verify_from_commit(this Secp256K1 self, Message msg, Signiture sig, Commitment commit) { if (self.Caps != ContextFlag.Commit) { throw new Exception("IncapableContext"); } // If we knew which one we cared about here we would just use it, // but for now return both so we can try them both. var pubkeys = commit.to_two_pubkeys(self); // Attempt to verify with the first public key, // if verify fails try the other one. // The first will fail on average 50% of the time. try { self.Verify(msg, sig, pubkeys[0]); } catch (Exception) { self.Verify(msg, sig, pubkeys[1]); } }