Skip to content

Instantly share code, notes, and snippets.

@marekyggdrasil
Last active February 3, 2023 12:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marekyggdrasil/45b164e8976e211cf7a6f982b16ba53d to your computer and use it in GitHub Desktop.
Save marekyggdrasil/45b164e8976e211cf7a6f982b16ba53d to your computer and use it in GitHub Desktop.
How to produce a Mimblewimble rangeproof and rewind it by @renzokuken
secp256k1_zkp_mw
bip32
hashlib
import os
from typing import List
from bip32 import BIP32
from hashlib import blake2b
from secp256k1_zkp_mw import SECP256K1_CONTEXT_SIGN
from secp256k1_zkp_mw import SECP256K1_CONTEXT_VERIFY
from secp256k1_zkp_mw import secp256k1_generator_const_h
from secp256k1_zkp_mw import secp256k1_generator_const_g
from secp256k1_zkp_mw import secp256k1_context_create
from secp256k1_zkp_mw import secp256k1_context_destroy
from secp256k1_zkp_mw import secp256k1_context_randomize
from secp256k1_zkp_mw import secp256k1_scratch_space_create
from secp256k1_zkp_mw import secp256k1_scratch_space_destroy
from secp256k1_zkp_mw import secp256k1_pedersen_commit
from secp256k1_zkp_mw import secp256k1_pedersen_commitment_serialize
from secp256k1_zkp_mw import secp256k1_bulletproof_generators_create
from secp256k1_zkp_mw import secp256k1_bulletproof_rangeproof_prove
from secp256k1_zkp_mw import secp256k1_bulletproof_rangeproof_rewind
from secp256k1_zkp_mw import secp256k1_ec_pubkey_parse
from secp256k1_zkp_mw import secp256k1_blind_switch
def getKeyIndices(path: str):
key_indices = []
for v in path.split('/'):
try:
i = int(v)
except:
continue
key_indices.append(i)
return key_indices
def proofMessageFromKeyIndices(
key_indices: List[int], is_enhanced=False):
padded_path = [0x00 for i in range(20)]
if is_enhanced:
# padded_path[0] 0x00 reserved
# padded_path[1] 0x00 is wallet type
padded_path[2] = 0x01 # switch commits
padded_path[3] = len(key_indices)
for i, key_index in enumerate(key_indices):
padded_path[i + 4] = key_index
return bytes(padded_path)
ctx = secp256k1_context_create(
SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)
MAX_WIDTH = 1 << 20
SCRATCH_SPACE_SIZE = 256 * MAX_WIDTH
MAX_GENERATORS = 256
x = bytes.fromhex(
'b860f56795fc03f3c21685383d1b5a2f2954f49b7e398b8d2a0193933621155f')
y = bytes.fromhex(
'a43f09d32caa8f53423f427403a56a3165a5a69a74cf56fc5901a2dca6c5c43a')
generator_j_pub = secp256k1_ec_pubkey_parse(
ctx, bytes([0x04]) + x + y)
generators = secp256k1_bulletproof_generators_create(
ctx, secp256k1_generator_const_g, MAX_GENERATORS);
amount = 45
path = 'm/0/1/0'
master_key = os.urandom(32)
key_indices = getKeyIndices(path)
bulletproof_nonce = secp256k1_blind_switch(
ctx,
master_key,
0,
secp256k1_generator_const_h,
secp256k1_generator_const_g,
generator_j_pub)
bip32 = BIP32(
chaincode=master_key[32:], privkey=master_key[:32])
secret_key = bip32.get_privkey_from_path(path)
assert secret_key == bip32.get_privkey_from_path(key_indices)
blinding_factor = secp256k1_blind_switch(
ctx,
secret_key,
amount,
secp256k1_generator_const_h,
secp256k1_generator_const_g,
generator_j_pub)
commitment = secp256k1_pedersen_commit(
ctx,
blinding_factor,
amount,
secp256k1_generator_const_h,
secp256k1_generator_const_g)
commitment_serialized = secp256k1_pedersen_commitment_serialize(
ctx, commitment)
nonce = blake2b(
commitment_serialized + bulletproof_nonce,
digest_size=32).digest()
proof_message = proofMessageFromKeyIndices(key_indices)
### GENERATE RANGEPROOF
seed = os.urandom(32)
secp256k1_context_randomize(ctx, seed)
scratch = secp256k1_scratch_space_create(
ctx, SCRATCH_SPACE_SIZE)
proof_bytes = secp256k1_bulletproof_rangeproof_prove(
ctx,
scratch,
generators,
None,
None,
None,
[amount],
None,
[blinding_factor],
None,
secp256k1_generator_const_h,
64,
nonce,
nonce,
None,
proof_message)
secp256k1_scratch_space_destroy(scratch)
### REWIND RANGEPROOF
value, blind, message_bytes = secp256k1_bulletproof_rangeproof_rewind(
ctx, proof_bytes, 0, commitment,
secp256k1_generator_const_h, nonce, None)
### TEST
assert value == amount
assert blind == blinding_factor
assert message_bytes == proof_message
print('everything works!')
secp256k1_context_destroy(ctx)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment