mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-21 19:14:19 +01:00
@@ -1,40 +1,32 @@
|
||||
# Don't trust me with cryptography.
|
||||
|
||||
"""
|
||||
Implementation of https://gist.github.com/RubenSomsen/be7a4760dd4596d06963d67baf140406
|
||||
|
||||
Alice:
|
||||
A = a*G
|
||||
return A
|
||||
|
||||
Bob:
|
||||
Y = hash_to_curve(secret_message)
|
||||
r = random blinding factor
|
||||
B'= Y + r*G
|
||||
return B'
|
||||
|
||||
Alice:
|
||||
C' = a*B'
|
||||
(= a*Y + a*r*G)
|
||||
return C'
|
||||
|
||||
Bob:
|
||||
C = C' - r*A
|
||||
(= C' - a*r*G)
|
||||
(= a*Y)
|
||||
return C, secret_message
|
||||
|
||||
Alice:
|
||||
Y = hash_to_curve(secret_message)
|
||||
C == a*Y
|
||||
|
||||
If true, C must have originated from Alice
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
|
||||
from ecc.curve import Point, secp256k1
|
||||
from ecc.key import gen_keypair
|
||||
|
||||
G = secp256k1.G
|
||||
from secp256k1 import PrivateKey, PublicKey
|
||||
|
||||
|
||||
def hash_to_curve(secret_msg):
|
||||
@@ -43,13 +35,15 @@ def hash_to_curve(secret_msg):
|
||||
point = None
|
||||
msg = secret_msg
|
||||
while point is None:
|
||||
x_coord = int(hashlib.sha256(msg).hexdigest().encode("utf-8"), 16)
|
||||
y_coord = secp256k1.compute_y(x_coord)
|
||||
_hash = hashlib.sha256(msg).hexdigest().encode("utf-8")
|
||||
try:
|
||||
# Fails if the point is not on the curve
|
||||
point = Point(x_coord, y_coord, secp256k1)
|
||||
# We construct compressed pub which has x coordinate encoded with even y
|
||||
_hash = list(_hash[:33]) # take the 33 bytes and get a list of bytes
|
||||
_hash[0] = 0x02 # set first byte to represent even y coord
|
||||
_hash = bytes(_hash)
|
||||
point = PublicKey(_hash, raw=True)
|
||||
except:
|
||||
msg = str(x_coord).encode("utf-8")
|
||||
msg = _hash
|
||||
|
||||
return point
|
||||
|
||||
@@ -57,35 +51,42 @@ def hash_to_curve(secret_msg):
|
||||
def step1_bob(secret_msg):
|
||||
secret_msg = secret_msg.encode("utf-8")
|
||||
Y = hash_to_curve(secret_msg)
|
||||
r, _ = gen_keypair(secp256k1)
|
||||
B_ = Y + r * G
|
||||
r = PrivateKey()
|
||||
B_ = Y + r.pubkey
|
||||
return B_, r
|
||||
|
||||
|
||||
def step2_alice(B_, a):
|
||||
C_ = a * B_
|
||||
C_ = B_.mult(a)
|
||||
return C_
|
||||
|
||||
|
||||
def step3_bob(C_, r, A):
|
||||
C = C_ - r * A
|
||||
C = C_ - A.mult(r)
|
||||
return C
|
||||
|
||||
|
||||
def verify(a, C, secret_msg):
|
||||
Y = hash_to_curve(secret_msg.encode("utf-8"))
|
||||
return C == a * Y
|
||||
return C == Y.mult(a)
|
||||
|
||||
|
||||
### Below is a test of a simple positive and negative case
|
||||
|
||||
# # Alice private key
|
||||
# a, A = gen_keypair(secp256k1)
|
||||
# # Alice's keys
|
||||
# a = PrivateKey()
|
||||
# A = a.pubkey
|
||||
# secret_msg = "test"
|
||||
# B_, r = step1_bob(secret_msg)
|
||||
# C_ = step2_alice(B_, a)
|
||||
# C = step3_bob(C_, r, A)
|
||||
# print("C:{}, secret_msg:{}".format(C, secret_msg))
|
||||
|
||||
# assert verify(a, C, secret_msg)
|
||||
# assert verify(a, C + 1*G, secret_msg) == False # adding 1*G shouldn't pass
|
||||
# assert verify(a, C + C, secret_msg) == False # adding C twice shouldn't pass
|
||||
# assert verify(a, A, secret_msg) == False # A shouldn't pass
|
||||
|
||||
# # Test operations
|
||||
# b = PrivateKey()
|
||||
# B = b.pubkey
|
||||
# assert -A -A + A == -A # neg
|
||||
# assert B.mult(a) == A.mult(b) # a*B = A*b
|
||||
|
||||
32
core/base.py
32
core/base.py
@@ -4,16 +4,9 @@ from typing import List
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class BasePoint(BaseModel):
|
||||
"""Named BasePoint because it conflicts with ecc.curve.Point"""
|
||||
|
||||
x: int
|
||||
y: int
|
||||
|
||||
|
||||
class Proof(BaseModel):
|
||||
amount: int
|
||||
C: BasePoint
|
||||
C: str
|
||||
secret: str
|
||||
reserved: bool = False # whether this proof is reserved for sending
|
||||
|
||||
@@ -21,22 +14,16 @@ class Proof(BaseModel):
|
||||
def from_row(cls, row: Row):
|
||||
return cls(
|
||||
amount=row[0],
|
||||
C=dict(
|
||||
x=int(row[1]),
|
||||
y=int(row[2]),
|
||||
),
|
||||
secret=row[3],
|
||||
reserved=row[4] or False,
|
||||
C=row[1],
|
||||
secret=row[2],
|
||||
reserved=row[3] or False,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: dict):
|
||||
return cls(
|
||||
amount=d["amount"],
|
||||
C=dict(
|
||||
x=int(d["C"]["x"]),
|
||||
y=int(d["C"]["y"]),
|
||||
),
|
||||
C=d["C"],
|
||||
secret=d["secret"],
|
||||
reserved=d["reserved"] or False,
|
||||
)
|
||||
@@ -72,21 +59,18 @@ class Invoice(BaseModel):
|
||||
|
||||
class BlindedMessage(BaseModel):
|
||||
amount: int
|
||||
B_: BasePoint
|
||||
B_: str
|
||||
|
||||
|
||||
class BlindedSignature(BaseModel):
|
||||
amount: int
|
||||
C_: BasePoint
|
||||
C_: str
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: dict):
|
||||
return cls(
|
||||
amount=d["amount"],
|
||||
C_=dict(
|
||||
x=int(d["C_"]["x"]),
|
||||
y=int(d["C_"]["y"]),
|
||||
),
|
||||
C_=d["C_"],
|
||||
)
|
||||
|
||||
|
||||
|
||||
52
core/secp.py
Normal file
52
core/secp.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from secp256k1 import PrivateKey, PublicKey
|
||||
|
||||
|
||||
# We extend the public key to define some operations on points
|
||||
# Picked from https://github.com/WTRMQDev/secp256k1-zkp-py/blob/master/secp256k1_zkp/__init__.py
|
||||
class PublicKeyExt(PublicKey):
|
||||
def __add__(self, pubkey2):
|
||||
if isinstance(pubkey2, PublicKey):
|
||||
new_pub = PublicKey()
|
||||
new_pub.combine([self.public_key, pubkey2.public_key])
|
||||
return new_pub
|
||||
else:
|
||||
raise TypeError("Cant add pubkey and %s" % pubkey2.__class__)
|
||||
|
||||
def __neg__(self):
|
||||
serialized = self.serialize()
|
||||
first_byte, remainder = serialized[:1], serialized[1:]
|
||||
# flip odd/even byte
|
||||
first_byte = {b"\x03": b"\x02", b"\x02": b"\x03"}[first_byte]
|
||||
return PublicKey(first_byte + remainder, raw=True)
|
||||
|
||||
def __sub__(self, pubkey2):
|
||||
if isinstance(pubkey2, PublicKey):
|
||||
return self + (-pubkey2)
|
||||
else:
|
||||
raise TypeError("Can't add pubkey and %s" % pubkey2.__class__)
|
||||
|
||||
def mult(self, privkey):
|
||||
if isinstance(privkey, PrivateKey):
|
||||
return self.tweak_mul(privkey.private_key)
|
||||
else:
|
||||
raise TypeError("Can't multiply with non privatekey")
|
||||
|
||||
def __eq__(self, pubkey2):
|
||||
if isinstance(pubkey2, PublicKey):
|
||||
seq1 = self.to_data()
|
||||
seq2 = pubkey2.to_data()
|
||||
return seq1 == seq2
|
||||
else:
|
||||
raise TypeError("Can't compare pubkey and %s" % pubkey2.__class__)
|
||||
|
||||
def to_data(self):
|
||||
return [self.public_key.data[i] for i in range(64)]
|
||||
|
||||
|
||||
# Horrible monkeypatching
|
||||
PublicKey.__add__ = PublicKeyExt.__add__
|
||||
PublicKey.__neg__ = PublicKeyExt.__neg__
|
||||
PublicKey.__sub__ = PublicKeyExt.__sub__
|
||||
PublicKey.mult = PublicKeyExt.mult
|
||||
PublicKey.__eq__ = PublicKeyExt.__eq__
|
||||
PublicKey.to_data = PublicKeyExt.to_data
|
||||
11
mint/app.py
11
mint/app.py
@@ -5,10 +5,11 @@ from typing import Union
|
||||
|
||||
import click
|
||||
import uvicorn
|
||||
from ecc.curve import Point, secp256k1
|
||||
from fastapi import FastAPI
|
||||
from loguru import logger
|
||||
|
||||
from secp256k1 import PublicKey
|
||||
|
||||
import core.settings as settings
|
||||
from core.base import MintPayloads, SplitPayload, MeltPayload, CheckPayload
|
||||
from core.settings import MINT_PRIVATE_KEY, MINT_SERVER_HOST, MINT_SERVER_PORT
|
||||
@@ -124,12 +125,8 @@ async def mint(payloads: MintPayloads, payment_hash: Union[str, None] = None):
|
||||
amounts = []
|
||||
B_s = []
|
||||
for payload in payloads.blinded_messages:
|
||||
v = payload.dict()
|
||||
amounts.append(v["amount"])
|
||||
x = int(v["B_"]["x"])
|
||||
y = int(v["B_"]["y"])
|
||||
B_ = Point(x, y, secp256k1)
|
||||
B_s.append(B_)
|
||||
amounts.append(payload.amount)
|
||||
B_s.append(PublicKey(bytes.fromhex(payload.B_), raw=True))
|
||||
try:
|
||||
promises = await ledger.mint(B_s, amounts, payment_hash=payment_hash)
|
||||
return promises
|
||||
|
||||
23
mint/crud.py
23
mint/crud.py
@@ -7,10 +7,8 @@ from core.db import Connection, Database
|
||||
|
||||
async def store_promise(
|
||||
amount: int,
|
||||
B_x: str,
|
||||
B_y: str,
|
||||
C_x: str,
|
||||
C_y: str,
|
||||
B_: str,
|
||||
C_: str,
|
||||
db: Database,
|
||||
conn: Optional[Connection] = None,
|
||||
):
|
||||
@@ -18,15 +16,13 @@ async def store_promise(
|
||||
await (conn or db).execute(
|
||||
"""
|
||||
INSERT INTO promises
|
||||
(amount, B_x, B_y, C_x, C_y)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
(amount, B_b, C_b)
|
||||
VALUES (?, ?, ?)
|
||||
""",
|
||||
(
|
||||
amount,
|
||||
str(B_x),
|
||||
str(B_y),
|
||||
str(C_x),
|
||||
str(C_y),
|
||||
str(B_),
|
||||
str(C_),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -54,13 +50,12 @@ async def invalidate_proof(
|
||||
await (conn or db).execute(
|
||||
"""
|
||||
INSERT INTO proofs_used
|
||||
(amount, C_x, C_y, secret)
|
||||
VALUES (?, ?, ?, ?)
|
||||
(amount, C, secret)
|
||||
VALUES (?, ?, ?)
|
||||
""",
|
||||
(
|
||||
proof.amount,
|
||||
str(proof.C.x),
|
||||
str(proof.C.y),
|
||||
str(proof.C),
|
||||
str(proof.secret),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -3,12 +3,10 @@ Implementation of https://gist.github.com/phyro/935badc682057f418842c72961cf096c
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import math
|
||||
from ecc.curve import Point, secp256k1
|
||||
from ecc.key import gen_keypair
|
||||
from core.secp import PrivateKey, PublicKey
|
||||
|
||||
from typing import List
|
||||
from core.base import Proof, BlindedMessage, BlindedSignature, BasePoint
|
||||
from typing import List, Set
|
||||
from core.base import Proof, BlindedMessage, BlindedSignature
|
||||
|
||||
import core.b_dhke as b_dhke
|
||||
from core.base import Invoice
|
||||
@@ -30,49 +28,49 @@ from mint.crud import (
|
||||
|
||||
class Ledger:
|
||||
def __init__(self, secret_key: str, db: str):
|
||||
self.proofs_used = set()
|
||||
self.proofs_used: Set[str] = set()
|
||||
|
||||
self.master_key = secret_key
|
||||
self.keys = self._derive_keys(self.master_key)
|
||||
self.pub_keys = self._derive_pubkeys(self.keys)
|
||||
self.db = Database("mint", db)
|
||||
self.master_key: str = secret_key
|
||||
self.keys: List[PrivateKey] = self._derive_keys(self.master_key)
|
||||
self.pub_keys: List[PublicKey] = self._derive_pubkeys(self.keys)
|
||||
self.db: Database = Database("mint", db)
|
||||
|
||||
async def load_used_proofs(self):
|
||||
self.proofs_used = set(await get_proofs_used(db=self.db))
|
||||
|
||||
@staticmethod
|
||||
def _derive_keys(master_key):
|
||||
def _derive_keys(master_key: str):
|
||||
"""Deterministic derivation of keys for 2^n values."""
|
||||
return {
|
||||
2
|
||||
** i: int(
|
||||
** i: PrivateKey(
|
||||
hashlib.sha256((str(master_key) + str(i)).encode("utf-8"))
|
||||
.hexdigest()
|
||||
.encode("utf-8"),
|
||||
16,
|
||||
.encode("utf-8")[:32],
|
||||
raw=True,
|
||||
)
|
||||
for i in range(MAX_ORDER)
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _derive_pubkeys(keys):
|
||||
return {
|
||||
amt: keys[amt] * secp256k1.G for amt in [2**i for i in range(MAX_ORDER)]
|
||||
}
|
||||
def _derive_pubkeys(keys: List[PrivateKey]):
|
||||
return {amt: keys[amt].pubkey for amt in [2**i for i in range(MAX_ORDER)]}
|
||||
|
||||
async def _generate_promises(self, amounts, B_s):
|
||||
"""Generates promises that sum to the given amount."""
|
||||
return [
|
||||
await self._generate_promise(amount, Point(B_.x, B_.y, secp256k1))
|
||||
await self._generate_promise(amount, PublicKey(bytes.fromhex(B_), raw=True))
|
||||
for (amount, B_) in zip(amounts, B_s)
|
||||
]
|
||||
|
||||
async def _generate_promise(self, amount: int, B_):
|
||||
async def _generate_promise(self, amount: int, B_: PublicKey):
|
||||
"""Generates a promise for given amount and returns a pair (amount, C')."""
|
||||
secret_key = self.keys[amount] # Get the correct key
|
||||
C_ = b_dhke.step2_alice(B_, secret_key)
|
||||
await store_promise(amount, B_x=B_.x, B_y=B_.y, C_x=C_.x, C_y=C_.y, db=self.db)
|
||||
return BlindedSignature(amount=amount, C_=BasePoint(x=C_.x, y=C_.y))
|
||||
await store_promise(
|
||||
amount, B_=B_.serialize().hex(), C_=C_.serialize().hex(), db=self.db
|
||||
)
|
||||
return BlindedSignature(amount=amount, C_=C_.serialize().hex())
|
||||
|
||||
def _check_spendable(self, proof: Proof):
|
||||
"""Checks whether the proof was already spent."""
|
||||
@@ -83,10 +81,12 @@ class Ledger:
|
||||
if not self._check_spendable(proof):
|
||||
raise Exception(f"tokens already spent. Secret: {proof.secret}")
|
||||
secret_key = self.keys[proof.amount] # Get the correct key to check against
|
||||
C = Point(proof.C.x, proof.C.y, secp256k1)
|
||||
C = PublicKey(bytes.fromhex(proof.C), raw=True)
|
||||
return b_dhke.verify(secret_key, C, proof.secret)
|
||||
|
||||
def _verify_outputs(self, total: int, amount: int, output_data):
|
||||
def _verify_outputs(
|
||||
self, total: int, amount: int, output_data: List[BlindedMessage]
|
||||
):
|
||||
"""Verifies the expected split was correctly computed"""
|
||||
fst_amt, snd_amt = total - amount, amount # we have two amounts to split to
|
||||
fst_outputs = amount_split(fst_amt)
|
||||
@@ -95,16 +95,18 @@ class Ledger:
|
||||
given = [o.amount for o in output_data]
|
||||
return given == expected
|
||||
|
||||
def _verify_no_duplicates(self, proofs: List[Proof], output_data):
|
||||
def _verify_no_duplicates(
|
||||
self, proofs: List[Proof], output_data: List[BlindedMessage]
|
||||
):
|
||||
secrets = [p.secret for p in proofs]
|
||||
if len(secrets) != len(list(set(secrets))):
|
||||
return False
|
||||
B_xs = [od.B_.x for od in output_data]
|
||||
if len(B_xs) != len(list(set(B_xs))):
|
||||
B_s = [od.B_ for od in output_data]
|
||||
if len(B_s) != len(list(set(B_s))):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _verify_split_amount(self, amount):
|
||||
def _verify_split_amount(self, amount: int):
|
||||
"""Split amount like output amount can't be negative or too big."""
|
||||
try:
|
||||
self._verify_amount(amount)
|
||||
@@ -179,7 +181,7 @@ class Ledger:
|
||||
# Public methods
|
||||
def get_pubkeys(self):
|
||||
"""Returns public keys for possible amounts."""
|
||||
return self.pub_keys
|
||||
return {a: p.serialize().hex() for a, p in self.pub_keys.items()}
|
||||
|
||||
async def request_mint(self, amount):
|
||||
"""Returns Lightning invoice and stores it in the db."""
|
||||
@@ -239,7 +241,7 @@ class Ledger:
|
||||
if not all([self._verify_proof(p) for p in proofs]):
|
||||
return False
|
||||
|
||||
total = sum([p["amount"] for p in proofs])
|
||||
total = sum([p.amount for p in proofs])
|
||||
|
||||
if not self._verify_no_duplicates(proofs, output_data):
|
||||
raise Exception("duplicate proofs or promises")
|
||||
|
||||
@@ -17,12 +17,10 @@ async def m001_initial(db: Database):
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS promises (
|
||||
amount INTEGER NOT NULL,
|
||||
B_x TEXT NOT NULL,
|
||||
B_y TEXT NOT NULL,
|
||||
C_x TEXT NOT NULL,
|
||||
C_y TEXT NOT NULL,
|
||||
B_b TEXT NOT NULL,
|
||||
C_b TEXT NOT NULL,
|
||||
|
||||
UNIQUE (B_x, B_y)
|
||||
UNIQUE (B_b)
|
||||
|
||||
);
|
||||
"""
|
||||
@@ -32,8 +30,7 @@ async def m001_initial(db: Database):
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS proofs_used (
|
||||
amount INTEGER NOT NULL,
|
||||
C_x TEXT NOT NULL,
|
||||
C_y TEXT NOT NULL,
|
||||
C TEXT NOT NULL,
|
||||
secret TEXT NOT NULL,
|
||||
|
||||
UNIQUE (secret)
|
||||
|
||||
44
poetry.lock
generated
44
poetry.lock
generated
@@ -127,40 +127,6 @@ category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "dataclasses"
|
||||
version = "0.6"
|
||||
description = "A backport of the dataclasses module for Python 3.6"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "ecc"
|
||||
version = "0.0.1"
|
||||
description = "Pure Python implementation of an elliptic curve cryptosystem based on FIPS 186-3"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "ecc-pycrypto"
|
||||
version = "1.0.0"
|
||||
description = ""
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
dataclasses = "*"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/lc6chang/ecc-pycrypto.git"
|
||||
reference = "v1.0.1"
|
||||
resolved_reference = "eb8b8c19a81a52d9cf705d90a597a78cdaf2b6f6"
|
||||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.18.0"
|
||||
@@ -707,7 +673,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "27d48020dabbc74117941ab884e1794d502d38c1380c777ee0edb203ada3c7b1"
|
||||
content-hash = "8046f708fe138fcdb9c1e39e18e4c466292f183f0d1736ecee66ec4854ad54cc"
|
||||
|
||||
[metadata.files]
|
||||
anyio = [
|
||||
@@ -838,14 +804,6 @@ colorama = [
|
||||
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
|
||||
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
|
||||
]
|
||||
dataclasses = [
|
||||
{file = "dataclasses-0.6-py3-none-any.whl", hash = "sha256:454a69d788c7fda44efd71e259be79577822f5e3f53f029a22d08004e951dc9f"},
|
||||
{file = "dataclasses-0.6.tar.gz", hash = "sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84"},
|
||||
]
|
||||
ecc = [
|
||||
{file = "ecc-0.0.1.zip", hash = "sha256:4bbcd46e9963ca37422d3244ab503af9dce95cbd35f676f7f9a4dd6306e23538"},
|
||||
]
|
||||
ecc-pycrypto = []
|
||||
ecdsa = [
|
||||
{file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"},
|
||||
{file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"},
|
||||
|
||||
@@ -8,7 +8,6 @@ license = "MIT"
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
pycrypto = "^2.6.1"
|
||||
ecc = "0.0.1"
|
||||
requests = "2.27.1"
|
||||
pytest-asyncio = "0.19.0"
|
||||
SQLAlchemy = "1.3.24"
|
||||
@@ -22,7 +21,6 @@ Jinja2 = "3.0.3"
|
||||
MarkupSafe = "2.1.1"
|
||||
urllib3 = "1.23"
|
||||
Werkzeug = "2.2.2"
|
||||
ecc-pycrypto = {git = "https://github.com/lc6chang/ecc-pycrypto.git", rev = "v1.0.1"}
|
||||
asgiref = "^3.5.2"
|
||||
pydantic = "^1.10.2"
|
||||
bech32 = "^1.2.0"
|
||||
|
||||
@@ -13,13 +13,12 @@ async def store_proof(
|
||||
await (conn or db).execute(
|
||||
"""
|
||||
INSERT INTO proofs
|
||||
(amount, C_x, C_y, secret)
|
||||
VALUES (?, ?, ?, ?)
|
||||
(amount, C, secret)
|
||||
VALUES (?, ?, ?)
|
||||
""",
|
||||
(
|
||||
proof.amount,
|
||||
str(proof.C.x),
|
||||
str(proof.C.y),
|
||||
str(proof.C),
|
||||
str(proof.secret),
|
||||
),
|
||||
)
|
||||
@@ -55,13 +54,12 @@ async def invalidate_proof(
|
||||
await (conn or db).execute(
|
||||
"""
|
||||
INSERT INTO proofs_used
|
||||
(amount, C_x, C_y, secret)
|
||||
VALUES (?, ?, ?, ?)
|
||||
(amount, C, secret)
|
||||
VALUES (?, ?, ?)
|
||||
""",
|
||||
(
|
||||
proof.amount,
|
||||
str(proof.C.x),
|
||||
str(proof.C.y),
|
||||
str(proof.C),
|
||||
str(proof.secret),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -17,8 +17,7 @@ async def m001_initial(db: Database):
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS proofs (
|
||||
amount INTEGER NOT NULL,
|
||||
C_x TEXT NOT NULL,
|
||||
C_y TEXT NOT NULL,
|
||||
C TEXT NOT NULL,
|
||||
secret TEXT NOT NULL,
|
||||
|
||||
UNIQUE (secret)
|
||||
@@ -31,8 +30,7 @@ async def m001_initial(db: Database):
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS proofs_used (
|
||||
amount INTEGER NOT NULL,
|
||||
C_x TEXT NOT NULL,
|
||||
C_y TEXT NOT NULL,
|
||||
C TEXT NOT NULL,
|
||||
secret TEXT NOT NULL,
|
||||
|
||||
UNIQUE (secret)
|
||||
|
||||
@@ -2,11 +2,10 @@ import random
|
||||
from typing import List
|
||||
|
||||
import requests
|
||||
from ecc.curve import Point, secp256k1
|
||||
from core.secp import PublicKey
|
||||
|
||||
import core.b_dhke as b_dhke
|
||||
from core.base import (
|
||||
BasePoint,
|
||||
BlindedMessage,
|
||||
MintPayloads,
|
||||
Proof,
|
||||
@@ -29,7 +28,8 @@ class LedgerAPI:
|
||||
def _get_keys(url):
|
||||
resp = requests.get(url + "/keys").json()
|
||||
return {
|
||||
int(amt): Point(val["x"], val["y"], secp256k1) for amt, val in resp.items()
|
||||
int(amt): PublicKey(bytes.fromhex(val), raw=True)
|
||||
for amt, val in resp.items()
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@@ -46,10 +46,9 @@ class LedgerAPI:
|
||||
"""Returns proofs of promise from promises."""
|
||||
proofs = []
|
||||
for promise, (r, secret) in zip(promises, secrets):
|
||||
C_ = Point(promise.C_.x, promise.C_.y, secp256k1)
|
||||
C_ = PublicKey(bytes.fromhex(promise.C_), raw=True)
|
||||
C = b_dhke.step3_bob(C_, r, self.keys[promise.amount])
|
||||
c_point = BasePoint(x=C.x, y=C.y)
|
||||
proof = Proof(amount=promise.amount, C=c_point, secret=secret)
|
||||
proof = Proof(amount=promise.amount, C=C.serialize().hex(), secret=secret)
|
||||
proofs.append(proof)
|
||||
return proofs
|
||||
|
||||
@@ -63,13 +62,14 @@ class LedgerAPI:
|
||||
payloads: MintPayloads = MintPayloads()
|
||||
secrets = []
|
||||
rs = []
|
||||
for i, amount in enumerate(amounts):
|
||||
for amount in amounts:
|
||||
secret = str(random.getrandbits(128))
|
||||
secrets.append(secret)
|
||||
B_, r = b_dhke.step1_bob(secret)
|
||||
rs.append(r)
|
||||
blinded_point = BasePoint(x=str(B_.x), y=str(B_.y))
|
||||
payload: BlindedMessage = BlindedMessage(amount=amount, B_=blinded_point)
|
||||
payload: BlindedMessage = BlindedMessage(
|
||||
amount=amount, B_=B_.serialize().hex()
|
||||
)
|
||||
payloads.blinded_messages.append(payload)
|
||||
promises_dict = requests.post(
|
||||
self.url + "/mint",
|
||||
@@ -94,9 +94,8 @@ class LedgerAPI:
|
||||
secret = str(random.getrandbits(128))
|
||||
B_, r = b_dhke.step1_bob(secret)
|
||||
secrets.append((r, secret))
|
||||
blinded_point = BasePoint(x=str(B_.x), y=str(B_.y))
|
||||
payload: BlindedMessage = BlindedMessage(
|
||||
amount=output_amt, B_=blinded_point
|
||||
amount=output_amt, B_=B_.serialize().hex()
|
||||
)
|
||||
payloads.blinded_messages.append(payload)
|
||||
split_payload = SplitPayload(proofs=proofs, amount=amount, output_data=payloads)
|
||||
|
||||
Reference in New Issue
Block a user