├── ecdsa ├── Verifier.toml ├── ellipticcurve │ ├── utils │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-38.pyc │ │ │ └── compatibility.cpython-38.pyc │ │ ├── file.py │ │ ├── integer.py │ │ ├── pem.py │ │ ├── binary.py │ │ ├── oid.py │ │ ├── compatibility.py │ │ └── der.py │ ├── __init__.py │ ├── point.py │ ├── main.py │ ├── signature.py │ ├── ecdsa.py │ ├── privateKey.py │ ├── curve.py │ ├── publicKey.py │ ├── math.py │ └── math1.py ├── Nargo.toml ├── Prover.toml ├── src │ ├── bigint │ │ ├── u32_utils.nr │ │ ├── tests.nr │ │ ├── division.nr │ │ └── arithmetic.nr │ ├── main.nr │ └── bigint.nr └── main.py ├── README.md ├── sha256 ├── sha256 │ ├── Nargo.toml │ ├── Prover.toml │ ├── Verifier.toml │ └── src │ │ └── main.nr ├── sha256.go └── sha256.py └── LICENSE /ecdsa/Verifier.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crypto-primatives 2 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ecdsa/Nargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [""] 3 | compiler_version = "0.1" 4 | 5 | [dependencies] -------------------------------------------------------------------------------- /sha256/sha256/Nargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [""] 3 | compiler_version = "0.1" 4 | 5 | [dependencies] -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelneuder/crypto-primitives/HEAD/ecdsa/ellipticcurve/utils/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/__pycache__/compatibility.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelneuder/crypto-primitives/HEAD/ecdsa/ellipticcurve/utils/__pycache__/compatibility.cpython-38.pyc -------------------------------------------------------------------------------- /ecdsa/Prover.toml: -------------------------------------------------------------------------------- 1 | x=[4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295] 2 | y=[4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295] -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/file.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class File: 4 | 5 | @classmethod 6 | def read(cls, path, mode="r"): 7 | with open(path, mode) as blob: 8 | content = blob.read() 9 | return content 10 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/__init__.py: -------------------------------------------------------------------------------- 1 | from .utils.compatibility import * 2 | from .privateKey import PrivateKey 3 | from .publicKey import PublicKey 4 | from .signature import Signature 5 | from .utils.file import File 6 | from .ecdsa import Ecdsa 7 | -------------------------------------------------------------------------------- /sha256/sha256/Prover.toml: -------------------------------------------------------------------------------- 1 | input = [97, 98, 99, 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, 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,] 2 | length = "3" -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/point.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Point: 4 | 5 | def __init__(self, x=0, y=0, z=0): 6 | self.x = x 7 | self.y = y 8 | self.z = z 9 | 10 | def __str__(self): 11 | return "({x}, {y}, {z})".format(x=self.x, y=self.y, z=self.z) 12 | 13 | def isAtInfinity(self): 14 | return self.y == 0 15 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/integer.py: -------------------------------------------------------------------------------- 1 | from random import SystemRandom 2 | 3 | 4 | class RandomInteger: 5 | 6 | @classmethod 7 | def between(cls, min, max): 8 | """ 9 | Return integer x in the range: min <= x <= max 10 | 11 | :param min: minimum value of the integer 12 | :param max: maximum value of the integer 13 | :return: 14 | """ 15 | 16 | return SystemRandom().randrange(min, max + 1) 17 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/pem.py: -------------------------------------------------------------------------------- 1 | from re import search 2 | 3 | 4 | def getPemContent(pem, template): 5 | pattern = template.format(content="(.*)") 6 | return search("".join(pattern.splitlines()), "".join(pem.splitlines())).group(1) 7 | 8 | 9 | def createPem(content, template): 10 | lines = [ 11 | content[start:start + 64] 12 | for start in range(0, len(content), 64) 13 | ] 14 | return template.format(content="\n".join(lines)) 15 | -------------------------------------------------------------------------------- /ecdsa/src/bigint/u32_utils.nr: -------------------------------------------------------------------------------- 1 | global U32_POW_2_0 : u32 = 1; 2 | global U32_POW_2_1 : u32 = 2; 3 | global U32_POW_2_3 : u32 = 8; 4 | global U32_POW_2_6 : u32 = 32; 5 | global U32_POW_2_7 : u32 = 128; 6 | global U32_POW_2_8 : u32 = 256; 7 | global U32_POW_2_14 : u32 = 16384; 8 | global U32_POW_2_16 : u32 = 65536; 9 | global U32_POW_2_24 : u32 = 16777216; 10 | global U32_MAX : u32 = 4294967295; 11 | 12 | fn shift_left_8(x : u32) -> u32 { 13 | x * U32_POW_2_8 14 | } 15 | 16 | fn shift_left_16(x : u32) -> u32 { 17 | x * U32_POW_2_16 18 | } 19 | 20 | fn shift_left_24(x : u32) -> u32 { 21 | x * U32_POW_2_24 22 | } -------------------------------------------------------------------------------- /ecdsa/main.py: -------------------------------------------------------------------------------- 1 | from json import dumps 2 | from ellipticcurve.ecdsa import Ecdsa 3 | from ellipticcurve.privateKey import PrivateKey 4 | 5 | 6 | # Generate privateKey from PEM string 7 | privateKey = PrivateKey.fromPem(""" 8 | -----BEGIN EC PARAMETERS----- 9 | BgUrgQQACg== 10 | -----END EC PARAMETERS----- 11 | -----BEGIN EC PRIVATE KEY----- 12 | MHQCAQEEIIS+XYQmfPFIAQ89W2C0KibWkHN4RCJajuiVOVNTnNSToAcGBSuBBAAK 13 | oUQDQgAEfDWvjeAYzBOjomTTFqEsatfCf+l2BkuY6PrH3IszscCTJNVRr/x1yeIf 14 | +CpQEMHTizQn5iITdeLeTx+VeAzFYg== 15 | -----END EC PRIVATE KEY----- 16 | """) 17 | 18 | message = "helloworld" 19 | 20 | signature = Ecdsa.sign(message, privateKey) 21 | 22 | # Generate Signature in base64. This result can be sent to Stark Bank in the request header as the Digital-Signature parameter. 23 | print(signature.toBase64()) 24 | 25 | # To double check if the message matches the signature, do this: 26 | publicKey = privateKey.publicKey() 27 | print(publicKey) 28 | 29 | print(Ecdsa.verify(message, signature, publicKey)) -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/binary.py: -------------------------------------------------------------------------------- 1 | from base64 import b64encode, b64decode 2 | from compatibility import safeHexFromBinary, safeBinaryFromHex, toString 3 | 4 | 5 | def hexFromInt(number): 6 | hexadecimal = "{0:x}".format(number) 7 | if len(hexadecimal) % 2 == 1: 8 | hexadecimal = "0" + hexadecimal 9 | return hexadecimal 10 | 11 | 12 | def intFromHex(hexadecimal): 13 | return int(hexadecimal, 16) 14 | 15 | 16 | def hexFromByteString(byteString): 17 | return safeHexFromBinary(byteString) 18 | 19 | 20 | def byteStringFromHex(hexadecimal): 21 | return safeBinaryFromHex(hexadecimal) 22 | 23 | 24 | def numberFromByteString(byteString): 25 | return intFromHex(hexFromByteString(byteString)) 26 | 27 | 28 | def base64FromByteString(byteString): 29 | return toString(b64encode(byteString)) 30 | 31 | 32 | def byteStringFromBase64(base64String): 33 | return b64decode(base64String) 34 | 35 | 36 | def bitsFromHex(hexadecimal): 37 | return format(intFromHex(hexadecimal), 'b').zfill(4 * len(hexadecimal)) 38 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/main.py: -------------------------------------------------------------------------------- 1 | from curve import CurveFp 2 | from point import Point 3 | 4 | 5 | secp256k1 = CurveFp( 6 | name="secp256k1", 7 | A=0x0000000000000000000000000000000000000000000000000000000000000000, 8 | B=0x0000000000000000000000000000000000000000000000000000000000000007, 9 | P=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, 10 | N=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141, 11 | Gx=0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 12 | Gy=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, 13 | oid=[1, 3, 132, 0, 10] 14 | ) 15 | 16 | print("general elliptic curve = y^2 = x^3 + Ax + B % P.") 17 | print("secp256k1 curve= y^2 = x^3 + 7.") 18 | print("prime of curve in decimal {:0d}".format(secp256k1.P)) 19 | 20 | res3 = secp256k1.y(3, isEven=False) 21 | print("sep256k1. when x=3, y={:0d}".format(res3)) 22 | 23 | point = Point( 24 | x=3, 25 | y=res3, 26 | ) 27 | 28 | print("confirming that point (x,y)=({}, {}) is on curve: {}".format(3, res3, secp256k1.contains(point))) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Mike Neuder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/oid.py: -------------------------------------------------------------------------------- 1 | from binary import intFromHex, hexFromInt 2 | 3 | 4 | def oidFromHex(hexadecimal): 5 | firstByte, remainingBytes = hexadecimal[:2], hexadecimal[2:] 6 | firstByteInt = intFromHex(firstByte) 7 | oid = [firstByteInt // 40, firstByteInt % 40] 8 | oidInt = 0 9 | while len(remainingBytes) > 0: 10 | byte, remainingBytes = remainingBytes[0:2], remainingBytes[2:] 11 | byteInt = intFromHex(byte) 12 | if byteInt >= 128: 13 | oidInt = (128 * oidInt) + (byteInt - 128) 14 | continue 15 | oidInt = (128 * oidInt) + byteInt 16 | oid.append(oidInt) 17 | oidInt = 0 18 | return oid 19 | 20 | 21 | def oidToHex(oid): 22 | hexadecimal = hexFromInt(40 * oid[0] + oid[1]) 23 | for number in oid[2:]: 24 | hexadecimal += _oidNumberToHex(number) 25 | return hexadecimal 26 | 27 | 28 | def _oidNumberToHex(number): 29 | hexadecimal = "" 30 | endDelta = 0 31 | while number > 0: 32 | hexadecimal = hexFromInt((number % 128) + endDelta) + hexadecimal 33 | number //= 128 34 | endDelta = 128 35 | return hexadecimal or "00" 36 | -------------------------------------------------------------------------------- /ecdsa/src/bigint/tests.nr: -------------------------------------------------------------------------------- 1 | // Tests 2 | fn run_tests() { 3 | test_from_bytes_be(); 4 | // test_add(); 5 | // test_mul(); 6 | // test_sub(); 7 | // test_sub_mul(); 8 | // test_msl(); 9 | // test_div_wide(); 10 | // test_div_rem_core(); 11 | } 12 | 13 | /// from_bytes_be 14 | fn test_from_bytes_be_case1() { 15 | // TODO: this line causes a weird bug that I think is related to MAX_BYTES existing in a diff function 16 | // let MAX_BYTES : comptime Field = NUM_LIMBS * LIMB_BYTES; 17 | let bytes = [1 as u8, 0, 1]; 18 | let bint = BigInt::from_bytes_le(bytes); 19 | constrain bint.limbs[0] == 1 + 65536; 20 | for i in 1..NUM_LIMBS { 21 | constrain bint.limbs[i] == 0; 22 | }; 23 | } 24 | 25 | fn test_from_bytes_be_case2() { 26 | let bytes = [ 27 | 0 as u8, 0, 0, 0, 28 | 0, 0, 0, 7, 29 | ]; 30 | let bint = BigInt::from_bytes_le(bytes); 31 | constrain bint.limbs[0] == 0; 32 | constrain bint.limbs[1] == 117440512; 33 | for i in 2..NUM_LIMBS { 34 | constrain bint.limbs[i] == 0; 35 | }; 36 | } 37 | 38 | fn test_from_bytes_be() { 39 | test_from_bytes_be_case1(); 40 | test_from_bytes_be_case2(); 41 | } -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/compatibility.py: -------------------------------------------------------------------------------- 1 | from sys import version_info as pyVersion 2 | from binascii import hexlify, unhexlify 3 | 4 | 5 | if pyVersion.major == 3: 6 | # py3 constants and conversion functions 7 | 8 | stringTypes = (str,) 9 | intTypes = (int, float) 10 | 11 | def toString(string, encoding="utf-8"): 12 | return string.decode(encoding) 13 | 14 | def toBytes(string, encoding="utf-8"): 15 | return string.encode(encoding) 16 | 17 | def safeBinaryFromHex(hexadecimal): 18 | if len(hexadecimal) % 2 == 1: 19 | hexadecimal = "0" + hexadecimal 20 | return unhexlify(hexadecimal) 21 | 22 | def safeHexFromBinary(byteString): 23 | return toString(hexlify(byteString)) 24 | else: 25 | # py2 constants and conversion functions 26 | 27 | stringTypes = (str, unicode) 28 | intTypes = (int, float, long) 29 | 30 | def toString(string, encoding="utf-8"): 31 | return string 32 | 33 | def toBytes(string, encoding="utf-8"): 34 | return string 35 | 36 | def safeBinaryFromHex(hexadecimal): 37 | return unhexlify(hexadecimal) 38 | 39 | def safeHexFromBinary(byteString): 40 | return hexlify(byteString) 41 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/signature.py: -------------------------------------------------------------------------------- 1 | from utils.compatibility import * 2 | from utils.der import parse, encodeConstructed, encodePrimitive, DerFieldType 3 | from utils.binary import hexFromByteString, byteStringFromHex, base64FromByteString, byteStringFromBase64 4 | 5 | 6 | class Signature: 7 | 8 | def __init__(self, r, s, recoveryId=None): 9 | self.r = r 10 | self.s = s 11 | self.recoveryId = recoveryId 12 | 13 | def toDer(self, withRecoveryId=False): 14 | hexadecimal = self._toString() 15 | encodedSequence = byteStringFromHex(hexadecimal) 16 | if not withRecoveryId: 17 | return encodedSequence 18 | return toBytes(chr(27 + self.recoveryId)) + encodedSequence 19 | 20 | def toBase64(self, withRecoveryId=False): 21 | return base64FromByteString(self.toDer(withRecoveryId)) 22 | 23 | @classmethod 24 | def fromDer(cls, string, recoveryByte=False): 25 | recoveryId = None 26 | if recoveryByte: 27 | recoveryId = string[0] if isinstance(string[0], intTypes) else ord(string[0]) 28 | recoveryId -= 27 29 | string = string[1:] 30 | 31 | hexadecimal = hexFromByteString(string) 32 | return cls._fromString(string=hexadecimal, recoveryId=recoveryId) 33 | 34 | @classmethod 35 | def fromBase64(cls, string, recoveryByte=False): 36 | der = byteStringFromBase64(string) 37 | return cls.fromDer(der, recoveryByte) 38 | 39 | def _toString(self): 40 | return encodeConstructed( 41 | encodePrimitive(DerFieldType.integer, self.r), 42 | encodePrimitive(DerFieldType.integer, self.s), 43 | ) 44 | 45 | @classmethod 46 | def _fromString(cls, string, recoveryId=None): 47 | r, s = parse(string)[0] 48 | return Signature(r=r, s=s, recoveryId=recoveryId) 49 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/ecdsa.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha256 2 | from signature import Signature 3 | from math import Math 4 | from utils.integer import RandomInteger 5 | from utils.binary import numberFromByteString 6 | from utils.compatibility import * 7 | 8 | 9 | class Ecdsa: 10 | 11 | @classmethod 12 | def sign(cls, message, privateKey, hashfunc=sha256): 13 | byteMessage = hashfunc(toBytes(message)).digest() 14 | numberMessage = numberFromByteString(byteMessage) 15 | curve = privateKey.curve 16 | 17 | r, s, randSignPoint = 0, 0, None 18 | while r == 0 or s == 0: 19 | randNum = RandomInteger.between(1, curve.N - 1) 20 | randSignPoint = Math.multiply(curve.G, n=randNum, A=curve.A, P=curve.P, N=curve.N) 21 | r = randSignPoint.x % curve.N 22 | s = ((numberMessage + r * privateKey.secret) * (Math.inv(randNum, curve.N))) % curve.N 23 | recoveryId = randSignPoint.y & 1 24 | if randSignPoint.y > curve.N: 25 | recoveryId += 2 26 | 27 | return Signature(r=r, s=s, recoveryId=recoveryId) 28 | 29 | @classmethod 30 | def verify(cls, message, signature, publicKey, hashfunc=sha256): 31 | byteMessage = hashfunc(toBytes(message)).digest() 32 | numberMessage = numberFromByteString(byteMessage) 33 | curve = publicKey.curve 34 | r = signature.r 35 | s = signature.s 36 | if not 1 <= r <= curve.N - 1: 37 | return False 38 | if not 1 <= s <= curve.N - 1: 39 | return False 40 | inv = Math.inv(s, curve.N) 41 | u1 = Math.multiply(curve.G, n=(numberMessage * inv) % curve.N, N=curve.N, A=curve.A, P=curve.P) 42 | u2 = Math.multiply(publicKey.point, n=(r * inv) % curve.N, N=curve.N, A=curve.A, P=curve.P) 43 | v = Math.add(u1, u2, A=curve.A, P=curve.P) 44 | if v.isAtInfinity(): 45 | return False 46 | return v.x % curve.N == r 47 | -------------------------------------------------------------------------------- /ecdsa/src/bigint/division.nr: -------------------------------------------------------------------------------- 1 | // Limb helpers (maybe turn into a struct) 2 | global U96_POW_2_32 : u96 = 4294967296; 3 | global U96_POW_2_64 : u96 = 18446744073709551616; 4 | fn to_triple_limb(hi : u32, mid : u32, lo : u32) -> u96 { 5 | (hi as u96 * U96_POW_2_64) | (mid as u96 * U96_POW_2_32) | (lo as u96) 6 | } 7 | 8 | /// Divide a three limb numerator by a two limb divisor, returns quotient and remainder: 9 | /// 10 | /// Note: the caller must ensure that both the quotient and remainder will fit into a single digit. 11 | /// This is _not_ true for an arbitrary numerator/denominator. 12 | fn div_wide(dividend_hi: u32, dividend_mid: u32, dividend_lo: u32, divisor_mid: u32, divisor_lo: u32) -> (u32, u64) { 13 | // TODO: debug_assert!(hi < divisor); 14 | let lhs = to_triple_limb(dividend_hi, dividend_mid, dividend_lo); 15 | let rhs = to_triple_limb(0, divisor_mid, divisor_lo); 16 | let q = lhs / rhs; 17 | let r = lhs - (rhs * q); 18 | (q as u32, r as u64) 19 | } 20 | 21 | /// For small divisors, we can divide without promoting to `DoubleBigDigit` by 22 | /// using half-size pieces of digit, like long-division. 23 | // fn div_half(rem: u32, digit: u32, divisor: u32) -> (u32, u32) { 24 | // // TODO: debug_assert!(rem < divisor && divisor <= HALF); 25 | // let (hi, rem) = ((rem << HALF_BITS) | (digit >> HALF_BITS)).div_rem(&divisor); 26 | // let (lo, rem) = ((rem << HALF_BITS) | (digit & HALF)).div_rem(&divisor); 27 | // ((hi << HALF_BITS) | lo, rem) 28 | // } 29 | 30 | /// Tests 31 | fn run_tests() { 32 | test_div_wide(); 33 | } 34 | 35 | // div_wide 36 | fn test_div_wide_case1() { 37 | let dividend_hi = 1; 38 | let dividend_mid = 0; 39 | let dividend_lo = 0; 40 | let divisor_mid = 5; 41 | let divisor_lo = 139; 42 | let expected_q = 858993453; 43 | let expected_r = 13743896209; 44 | let (q, r) = div_wide(dividend_hi, dividend_mid, dividend_lo, divisor_mid, divisor_lo); 45 | constrain expected_q == q; 46 | constrain expected_r == r; 47 | } 48 | 49 | fn test_div_wide() { 50 | test_div_wide_case1(); 51 | } 52 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/privateKey.py: -------------------------------------------------------------------------------- 1 | from math import Math 2 | from utils.integer import RandomInteger 3 | from utils.pem import getPemContent, createPem 4 | from utils.binary import hexFromByteString, byteStringFromHex, intFromHex, base64FromByteString, byteStringFromBase64 5 | from utils.der import hexFromInt, parse, encodeConstructed, DerFieldType, encodePrimitive 6 | from curve import secp256k1, getByOid 7 | from publicKey import PublicKey 8 | 9 | 10 | class PrivateKey: 11 | 12 | def __init__(self, curve=secp256k1, secret=None): 13 | self.curve = curve 14 | self.secret = secret or RandomInteger.between(1, curve.N - 1) 15 | 16 | def publicKey(self): 17 | curve = self.curve 18 | publicPoint = Math.multiply( 19 | p=curve.G, 20 | n=self.secret, 21 | N=curve.N, 22 | A=curve.A, 23 | P=curve.P, 24 | ) 25 | return PublicKey(point=publicPoint, curve=curve) 26 | 27 | def toString(self): 28 | return hexFromInt(self.secret) 29 | 30 | def toDer(self): 31 | publicKeyString = self.publicKey().toString(encoded=True) 32 | hexadecimal = encodeConstructed( 33 | encodePrimitive(DerFieldType.integer, 1), 34 | encodePrimitive(DerFieldType.octetString, hexFromInt(self.secret)), 35 | encodePrimitive(DerFieldType.oidContainer, encodePrimitive(DerFieldType.object, self.curve.oid)), 36 | encodePrimitive(DerFieldType.publicKeyPointContainer, encodePrimitive(DerFieldType.bitString, publicKeyString)) 37 | ) 38 | return byteStringFromHex(hexadecimal) 39 | 40 | def toPem(self): 41 | der = self.toDer() 42 | return createPem(content=base64FromByteString(der), template=_pemTemplate) 43 | 44 | @classmethod 45 | def fromPem(cls, string): 46 | privateKeyPem = getPemContent(pem=string, template=_pemTemplate) 47 | return cls.fromDer(byteStringFromBase64(privateKeyPem)) 48 | 49 | @classmethod 50 | def fromDer(cls, string): 51 | hexadecimal = hexFromByteString(string) 52 | privateKeyFlag, secretHex, curveData, publicKeyString = parse(hexadecimal)[0] 53 | if privateKeyFlag != 1: 54 | raise Exception("Private keys should start with a '1' flag, but a '{flag}' was found instead".format( 55 | flag=privateKeyFlag 56 | )) 57 | curve = getByOid(curveData[0]) 58 | privateKey = cls.fromString(string=secretHex, curve=curve) 59 | if privateKey.publicKey().toString(encoded=True) != publicKeyString[0]: 60 | raise Exception("The public key described inside the private key file doesn't match the actual public key of the pair") 61 | return privateKey 62 | 63 | @classmethod 64 | def fromString(cls, string, curve=secp256k1): 65 | return PrivateKey(secret=intFromHex(string), curve=curve) 66 | 67 | 68 | _pemTemplate = """ 69 | -----BEGIN EC PRIVATE KEY----- 70 | {content} 71 | -----END EC PRIVATE KEY----- 72 | """ 73 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/curve.py: -------------------------------------------------------------------------------- 1 | # 2 | # Elliptic Curve Equation 3 | # 4 | # y^2 = x^3 + A*x + B (mod P) 5 | # 6 | from math1 import Math1 7 | from point import Point 8 | 9 | 10 | class CurveFp: 11 | 12 | def __init__(self, A, B, P, N, Gx, Gy, name, oid, nistName=None): 13 | self.A = A 14 | self.B = B 15 | self.P = P 16 | self.N = N 17 | self.G = Point(Gx, Gy) 18 | self.name = name 19 | self.nistName = nistName 20 | self.oid = oid # ASN.1 Object Identifier 21 | 22 | def contains(self, p): 23 | """ 24 | Verify if the point `p` is on the curve 25 | 26 | :param p: Point p = Point(x, y) 27 | :return: boolean 28 | """ 29 | if not 0 <= p.x <= self.P - 1: 30 | return False 31 | if not 0 <= p.y <= self.P - 1: 32 | return False 33 | if (p.y**2 - (p.x**3 + self.A * p.x + self.B)) % self.P != 0: 34 | return False 35 | return True 36 | 37 | def length(self): 38 | return (1 + len("%x" % self.N)) // 2 39 | 40 | def y(self, x, isEven): 41 | ySquared = (pow(x, 3, self.P) + self.A * x + self.B) % self.P 42 | y = Math1.modularSquareRoot(ySquared, self.P) 43 | if isEven != (y % 2 == 0): 44 | y = self.P - y 45 | return y 46 | 47 | 48 | _curvesByOid = {tuple(curve.oid): curve for curve in []} 49 | 50 | 51 | def add(curve): 52 | _curvesByOid[tuple(curve.oid)] = curve 53 | 54 | 55 | def getByOid(oid): 56 | if oid not in _curvesByOid: 57 | raise Exception("Unknown curve with oid {oid}; The following are registered: {names}".format( 58 | oid=".".join([str(number) for number in oid]), 59 | names=", ".join([curve.name for curve in _curvesByOid.values()]), 60 | )) 61 | return _curvesByOid[oid] 62 | 63 | 64 | secp256k1 = CurveFp( 65 | name="secp256k1", 66 | A=0x0000000000000000000000000000000000000000000000000000000000000000, 67 | B=0x0000000000000000000000000000000000000000000000000000000000000007, 68 | P=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, 69 | N=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141, 70 | Gx=0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 71 | Gy=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, 72 | oid=[1, 3, 132, 0, 10] 73 | ) 74 | 75 | prime256v1 = CurveFp( 76 | name="prime256v1", 77 | nistName="P-256", 78 | A=0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc, 79 | B=0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b, 80 | P=0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff, 81 | N=0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551, 82 | Gx=0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 83 | Gy=0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, 84 | oid=[1, 2, 840, 10045, 3, 1, 7], 85 | ) 86 | 87 | p256 = prime256v1 88 | 89 | add(secp256k1) 90 | add(prime256v1) 91 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/publicKey.py: -------------------------------------------------------------------------------- 1 | from math import Math 2 | from point import Point 3 | from curve import secp256k1, getByOid 4 | from utils.pem import getPemContent, createPem 5 | from utils.der import hexFromInt, parse, DerFieldType, encodeConstructed, encodePrimitive 6 | from utils.binary import hexFromByteString, byteStringFromHex, intFromHex, base64FromByteString, byteStringFromBase64 7 | 8 | 9 | class PublicKey: 10 | 11 | def __init__(self, point, curve): 12 | self.point = point 13 | self.curve = curve 14 | 15 | def toString(self, encoded=False): 16 | baseLength = 2 * self.curve.length() 17 | xHex = hexFromInt(self.point.x).zfill(baseLength) 18 | yHex = hexFromInt(self.point.y).zfill(baseLength) 19 | string = xHex + yHex 20 | if encoded: 21 | return "0004" + string 22 | return string 23 | 24 | def toCompressed(self): 25 | baseLength = 2 * self.curve.length() 26 | parityTag = _evenTag if self.point.y % 2 == 0 else _oddTag 27 | xHex = hexFromInt(self.point.x).zfill(baseLength) 28 | return parityTag + xHex 29 | 30 | def toDer(self): 31 | hexadecimal = encodeConstructed( 32 | encodeConstructed( 33 | encodePrimitive(DerFieldType.object, _ecdsaPublicKeyOid), 34 | encodePrimitive(DerFieldType.object, self.curve.oid), 35 | ), 36 | encodePrimitive(DerFieldType.bitString, self.toString(encoded=True)), 37 | ) 38 | return byteStringFromHex(hexadecimal) 39 | 40 | def toPem(self): 41 | der = self.toDer() 42 | return createPem(content=base64FromByteString(der), template=_pemTemplate) 43 | 44 | @classmethod 45 | def fromPem(cls, string): 46 | publicKeyPem = getPemContent(pem=string, template=_pemTemplate) 47 | return cls.fromDer(byteStringFromBase64(publicKeyPem)) 48 | 49 | @classmethod 50 | def fromDer(cls, string): 51 | hexadecimal = hexFromByteString(string) 52 | curveData, pointString = parse(hexadecimal)[0] 53 | publicKeyOid, curveOid = curveData 54 | if publicKeyOid != _ecdsaPublicKeyOid: 55 | raise Exception("The Public Key Object Identifier (OID) should be {ecdsaPublicKeyOid}, but {actualOid} was found instead".format( 56 | ecdsaPublicKeyOid=_ecdsaPublicKeyOid, 57 | actualOid=publicKeyOid, 58 | )) 59 | curve = getByOid(curveOid) 60 | return cls.fromString(string=pointString, curve=curve) 61 | 62 | @classmethod 63 | def fromString(cls, string, curve=secp256k1, validatePoint=True): 64 | baseLength = 2 * curve.length() 65 | if len(string) > 2 * baseLength and string[:4] == "0004": 66 | string = string[4:] 67 | 68 | xs = string[:baseLength] 69 | ys = string[baseLength:] 70 | 71 | p = Point( 72 | x=intFromHex(xs), 73 | y=intFromHex(ys), 74 | ) 75 | publicKey = PublicKey(point=p, curve=curve) 76 | if not validatePoint: 77 | return publicKey 78 | if p.isAtInfinity(): 79 | raise Exception("Public Key point is at infinity") 80 | if not curve.contains(p): 81 | raise Exception("Point ({x},{y}) is not valid for curve {name}".format(x=p.x, y=p.y, name=curve.name)) 82 | if not Math.multiply(p=p, n=curve.N, N=curve.N, A=curve.A, P=curve.P).isAtInfinity(): 83 | raise Exception("Point ({x},{y}) * {name}.N is not at infinity".format(x=p.x, y=p.y, name=curve.name)) 84 | return publicKey 85 | 86 | @classmethod 87 | def fromCompressed(cls, string, curve=secp256k1): 88 | parityTag, xHex = string[:2], string[2:] 89 | if parityTag not in [_evenTag, _oddTag]: 90 | raise Exception("Compressed string should start with 02 or 03") 91 | x = intFromHex(xHex) 92 | y = curve.y(x, isEven=parityTag == _evenTag) 93 | return cls(point=Point(x, y), curve=curve) 94 | 95 | 96 | _evenTag = "02" 97 | _oddTag = "03" 98 | 99 | 100 | _ecdsaPublicKeyOid = (1, 2, 840, 10045, 2, 1) 101 | 102 | 103 | _pemTemplate = """ 104 | -----BEGIN PUBLIC KEY----- 105 | {content} 106 | -----END PUBLIC KEY----- 107 | """ 108 | -------------------------------------------------------------------------------- /sha256/sha256/Verifier.toml: -------------------------------------------------------------------------------- 1 | input = ["0x0000000000000000000000000000000000000000000000000000000000000061", "0x0000000000000000000000000000000000000000000000000000000000000062", "0x0000000000000000000000000000000000000000000000000000000000000063", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"] 2 | length = "0x0000000000000000000000000000000000000000000000000000000000000003" 3 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/utils/der.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from oid import oidToHex, oidFromHex 3 | from binary import hexFromInt, intFromHex, byteStringFromHex, bitsFromHex 4 | 5 | 6 | class DerFieldType: 7 | 8 | integer = "integer" 9 | bitString = "bitString" 10 | octetString = "octetString" 11 | null = "null" 12 | object = "object" 13 | printableString = "printableString" 14 | utcTime = "utcTime" 15 | sequence = "sequence" 16 | set = "set" 17 | oidContainer = "oidContainer" 18 | publicKeyPointContainer = "publicKeyPointContainer" 19 | 20 | 21 | _hexTagToType = { 22 | "02": DerFieldType.integer, 23 | "03": DerFieldType.bitString, 24 | "04": DerFieldType.octetString, 25 | "05": DerFieldType.null, 26 | "06": DerFieldType.object, 27 | "13": DerFieldType.printableString, 28 | "17": DerFieldType.utcTime, 29 | "30": DerFieldType.sequence, 30 | "31": DerFieldType.set, 31 | "a0": DerFieldType.oidContainer, 32 | "a1": DerFieldType.publicKeyPointContainer, 33 | } 34 | _typeToHexTag = {v: k for k, v in _hexTagToType.items()} 35 | 36 | 37 | def encodeConstructed(*encodedValues): 38 | return encodePrimitive(DerFieldType.sequence, "".join(encodedValues)) 39 | 40 | 41 | def encodePrimitive(tagType, value): 42 | if tagType == DerFieldType.integer: 43 | value = _encodeInteger(value) 44 | if tagType == DerFieldType.object: 45 | value = oidToHex(value) 46 | return "{tag}{size}{value}".format(tag=_typeToHexTag[tagType], size=_generateLengthBytes(value), value=value) 47 | 48 | 49 | def parse(hexadecimal): 50 | if not hexadecimal: 51 | return [] 52 | typeByte, hexadecimal = hexadecimal[:2], hexadecimal[2:] 53 | length, lengthBytes = _readLengthBytes(hexadecimal) 54 | content, hexadecimal = hexadecimal[lengthBytes: lengthBytes + length], hexadecimal[lengthBytes + length:] 55 | if len(content) < length: 56 | raise Exception("missing bytes in DER parse") 57 | 58 | tagData = _getTagData(typeByte) 59 | if tagData["isConstructed"]: 60 | content = parse(content) 61 | 62 | valueParser = { 63 | DerFieldType.null: _parseNull, 64 | DerFieldType.object: _parseOid, 65 | DerFieldType.utcTime: _parseTime, 66 | DerFieldType.integer: _parseInteger, 67 | DerFieldType.printableString: _parseString, 68 | }.get(tagData["type"], _parseAny) 69 | return [valueParser(content)] + parse(hexadecimal) 70 | 71 | 72 | def _parseAny(hexadecimal): 73 | return hexadecimal 74 | 75 | 76 | def _parseOid(hexadecimal): 77 | return tuple(oidFromHex(hexadecimal)) 78 | 79 | 80 | def _parseTime(hexadecimal): 81 | string = _parseString(hexadecimal) 82 | return datetime.strptime(string, "%y%m%d%H%M%SZ") 83 | 84 | 85 | def _parseString(hexadecimal): 86 | return byteStringFromHex(hexadecimal).decode() 87 | 88 | 89 | def _parseNull(_content): 90 | return None 91 | 92 | 93 | def _parseInteger(hexadecimal): 94 | integer = intFromHex(hexadecimal) 95 | bits = bitsFromHex(hexadecimal[0]) 96 | if bits[0] == "0": # negative numbers are encoded using two's complement 97 | return integer 98 | bitCount = 4 * len(hexadecimal) 99 | return integer - (2 ** bitCount) 100 | 101 | 102 | def _encodeInteger(number): 103 | hexadecimal = hexFromInt(abs(number)) 104 | if number < 0: 105 | bitCount = 4 * len(hexadecimal) 106 | twosComplement = (2 ** bitCount) + number 107 | return hexFromInt(twosComplement) 108 | bits = bitsFromHex(hexadecimal[0]) 109 | if bits[0] == "1": # if first bit was left as 1, number would be parsed as a negative integer with two's complement 110 | hexadecimal = "00" + hexadecimal 111 | return hexadecimal 112 | 113 | 114 | def _readLengthBytes(hexadecimal): 115 | lengthBytes = 2 116 | lengthIndicator = intFromHex(hexadecimal[0:lengthBytes]) 117 | isShortForm = lengthIndicator < 128 # checks if first bit of byte is 1 (a.k.a. short-form) 118 | if isShortForm: 119 | length = lengthIndicator * 2 120 | return length, lengthBytes 121 | 122 | lengthLength = lengthIndicator - 128 # nullifies first bit of byte (only used as long-form flag) 123 | if lengthLength == 0: 124 | raise Exception("indefinite length encoding located in DER") 125 | lengthBytes += 2 * lengthLength 126 | length = intFromHex(hexadecimal[2:lengthBytes]) * 2 127 | return length, lengthBytes 128 | 129 | 130 | def _generateLengthBytes(hexadecimal): 131 | size = len(hexadecimal) // 2 132 | length = hexFromInt(size) 133 | if size < 128: # checks if first bit of byte should be 0 (a.k.a. short-form flag) 134 | return length.zfill(2) 135 | lengthLength = 128 + len(length) // 2 # +128 sets the first bit of the byte as 1 (a.k.a. long-form flag) 136 | return hexFromInt(lengthLength) + length 137 | 138 | 139 | def _getTagData(tag): 140 | bits = bitsFromHex(tag) 141 | bit8, bit7, bit6 = bits[:3] 142 | 143 | tagClass = { 144 | "0": { 145 | "0": "universal", 146 | "1": "application", 147 | }, 148 | "1": { 149 | "0": "context-specific", 150 | "1": "private", 151 | }, 152 | }[bit8][bit7] 153 | isConstructed = bit6 == "1" 154 | 155 | return { 156 | "class": tagClass, 157 | "isConstructed": isConstructed, 158 | "type": _hexTagToType.get(tag), 159 | } 160 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/math.py: -------------------------------------------------------------------------------- 1 | from .point import Point 2 | 3 | 4 | class Math: 5 | 6 | @classmethod 7 | def modularSquareRoot(cls, value, prime): 8 | return pow(value, (prime + 1) // 4, prime) 9 | 10 | @classmethod 11 | def multiply(cls, p, n, N, A, P): 12 | """ 13 | Fast way to multily point and scalar in elliptic curves 14 | 15 | :param p: First Point to mutiply 16 | :param n: Scalar to mutiply 17 | :param N: Order of the elliptic curve 18 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 19 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 20 | :return: Point that represents the sum of First and Second Point 21 | """ 22 | return cls._fromJacobian( 23 | cls._jacobianMultiply(cls._toJacobian(p), n, N, A, P), P 24 | ) 25 | 26 | @classmethod 27 | def add(cls, p, q, A, P): 28 | """ 29 | Fast way to add two points in elliptic curves 30 | 31 | :param p: First Point you want to add 32 | :param q: Second Point you want to add 33 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 34 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 35 | :return: Point that represents the sum of First and Second Point 36 | """ 37 | return cls._fromJacobian( 38 | cls._jacobianAdd(cls._toJacobian(p), cls._toJacobian(q), A, P), P, 39 | ) 40 | 41 | @classmethod 42 | def inv(cls, x, n): 43 | """ 44 | Extended Euclidean Algorithm. It's the 'division' in elliptic curves 45 | 46 | :param x: Divisor 47 | :param n: Mod for division 48 | :return: Value representing the division 49 | """ 50 | if x == 0: 51 | return 0 52 | 53 | lm = 1 54 | hm = 0 55 | low = x % n 56 | high = n 57 | 58 | while low > 1: 59 | r = high // low 60 | nm = hm - lm * r 61 | nw = high - low * r 62 | high = low 63 | hm = lm 64 | low = nw 65 | lm = nm 66 | 67 | return lm % n 68 | 69 | @classmethod 70 | def _toJacobian(cls, p): 71 | """ 72 | Convert point to Jacobian coordinates 73 | 74 | :param p: First Point you want to add 75 | :return: Point in Jacobian coordinates 76 | """ 77 | return Point(p.x, p.y, 1) 78 | 79 | @classmethod 80 | def _fromJacobian(cls, p, P): 81 | """ 82 | Convert point back from Jacobian coordinates 83 | 84 | :param p: First Point you want to add 85 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 86 | :return: Point in default coordinates 87 | """ 88 | z = cls.inv(p.z, P) 89 | x = (p.x * z ** 2) % P 90 | y = (p.y * z ** 3) % P 91 | 92 | return Point(x, y, 0) 93 | 94 | @classmethod 95 | def _jacobianDouble(cls, p, A, P): 96 | """ 97 | Double a point in elliptic curves 98 | 99 | :param p: Point you want to double 100 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 101 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 102 | :return: Point that represents the sum of First and Second Point 103 | """ 104 | if p.y == 0: 105 | return Point(0, 0, 0) 106 | 107 | ysq = (p.y ** 2) % P 108 | S = (4 * p.x * ysq) % P 109 | M = (3 * p.x ** 2 + A * p.z ** 4) % P 110 | nx = (M**2 - 2 * S) % P 111 | ny = (M * (S - nx) - 8 * ysq ** 2) % P 112 | nz = (2 * p.y * p.z) % P 113 | 114 | return Point(nx, ny, nz) 115 | 116 | @classmethod 117 | def _jacobianAdd(cls, p, q, A, P): 118 | """ 119 | Add two points in elliptic curves 120 | 121 | :param p: First Point you want to add 122 | :param q: Second Point you want to add 123 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 124 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 125 | :return: Point that represents the sum of First and Second Point 126 | """ 127 | if p.y == 0: 128 | return q 129 | if q.y == 0: 130 | return p 131 | 132 | U1 = (p.x * q.z ** 2) % P 133 | U2 = (q.x * p.z ** 2) % P 134 | S1 = (p.y * q.z ** 3) % P 135 | S2 = (q.y * p.z ** 3) % P 136 | 137 | if U1 == U2: 138 | if S1 != S2: 139 | return Point(0, 0, 1) 140 | return cls._jacobianDouble(p, A, P) 141 | 142 | H = U2 - U1 143 | R = S2 - S1 144 | H2 = (H * H) % P 145 | H3 = (H * H2) % P 146 | U1H2 = (U1 * H2) % P 147 | nx = (R ** 2 - H3 - 2 * U1H2) % P 148 | ny = (R * (U1H2 - nx) - S1 * H3) % P 149 | nz = (H * p.z * q.z) % P 150 | 151 | return Point(nx, ny, nz) 152 | 153 | @classmethod 154 | def _jacobianMultiply(cls, p, n, N, A, P): 155 | """ 156 | Multily point and scalar in elliptic curves 157 | 158 | :param p: First Point to mutiply 159 | :param n: Scalar to mutiply 160 | :param N: Order of the elliptic curve 161 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 162 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 163 | :return: Point that represents the sum of First and Second Point 164 | """ 165 | if p.y == 0 or n == 0: 166 | return Point(0, 0, 1) 167 | 168 | if n == 1: 169 | return p 170 | 171 | if n < 0 or n >= N: 172 | return cls._jacobianMultiply(p, n % N, N, A, P) 173 | 174 | if (n % 2) == 0: 175 | return cls._jacobianDouble( 176 | cls._jacobianMultiply(p, n // 2, N, A, P), A, P 177 | ) 178 | 179 | return cls._jacobianAdd( 180 | cls._jacobianDouble(cls._jacobianMultiply(p, n // 2, N, A, P), A, P), p, A, P 181 | ) 182 | -------------------------------------------------------------------------------- /ecdsa/ellipticcurve/math1.py: -------------------------------------------------------------------------------- 1 | from point import Point 2 | 3 | 4 | class Math1: 5 | 6 | @classmethod 7 | def modularSquareRoot(cls, value, prime): 8 | return pow(value, (prime + 1) // 4, prime) 9 | 10 | @classmethod 11 | def multiply(cls, p, n, N, A, P): 12 | """ 13 | Fast way to multily point and scalar in elliptic curves 14 | 15 | :param p: First Point to mutiply 16 | :param n: Scalar to mutiply 17 | :param N: Order of the elliptic curve 18 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 19 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 20 | :return: Point that represents the sum of First and Second Point 21 | """ 22 | return cls._fromJacobian( 23 | cls._jacobianMultiply(cls._toJacobian(p), n, N, A, P), P 24 | ) 25 | 26 | @classmethod 27 | def add(cls, p, q, A, P): 28 | """ 29 | Fast way to add two points in elliptic curves 30 | 31 | :param p: First Point you want to add 32 | :param q: Second Point you want to add 33 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 34 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 35 | :return: Point that represents the sum of First and Second Point 36 | """ 37 | return cls._fromJacobian( 38 | cls._jacobianAdd(cls._toJacobian(p), cls._toJacobian(q), A, P), P, 39 | ) 40 | 41 | @classmethod 42 | def inv(cls, x, n): 43 | """ 44 | Extended Euclidean Algorithm. It's the 'division' in elliptic curves 45 | 46 | :param x: Divisor 47 | :param n: Mod for division 48 | :return: Value representing the division 49 | """ 50 | if x == 0: 51 | return 0 52 | 53 | lm = 1 54 | hm = 0 55 | low = x % n 56 | high = n 57 | 58 | while low > 1: 59 | r = high // low 60 | nm = hm - lm * r 61 | nw = high - low * r 62 | high = low 63 | hm = lm 64 | low = nw 65 | lm = nm 66 | 67 | return lm % n 68 | 69 | @classmethod 70 | def _toJacobian(cls, p): 71 | """ 72 | Convert point to Jacobian coordinates 73 | 74 | :param p: First Point you want to add 75 | :return: Point in Jacobian coordinates 76 | """ 77 | return Point(p.x, p.y, 1) 78 | 79 | @classmethod 80 | def _fromJacobian(cls, p, P): 81 | """ 82 | Convert point back from Jacobian coordinates 83 | 84 | :param p: First Point you want to add 85 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 86 | :return: Point in default coordinates 87 | """ 88 | z = cls.inv(p.z, P) 89 | x = (p.x * z ** 2) % P 90 | y = (p.y * z ** 3) % P 91 | 92 | return Point(x, y, 0) 93 | 94 | @classmethod 95 | def _jacobianDouble(cls, p, A, P): 96 | """ 97 | Double a point in elliptic curves 98 | 99 | :param p: Point you want to double 100 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 101 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 102 | :return: Point that represents the sum of First and Second Point 103 | """ 104 | if p.y == 0: 105 | return Point(0, 0, 0) 106 | 107 | ysq = (p.y ** 2) % P 108 | S = (4 * p.x * ysq) % P 109 | M = (3 * p.x ** 2 + A * p.z ** 4) % P 110 | nx = (M**2 - 2 * S) % P 111 | ny = (M * (S - nx) - 8 * ysq ** 2) % P 112 | nz = (2 * p.y * p.z) % P 113 | 114 | return Point(nx, ny, nz) 115 | 116 | @classmethod 117 | def _jacobianAdd(cls, p, q, A, P): 118 | """ 119 | Add two points in elliptic curves 120 | 121 | :param p: First Point you want to add 122 | :param q: Second Point you want to add 123 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 124 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 125 | :return: Point that represents the sum of First and Second Point 126 | """ 127 | if p.y == 0: 128 | return q 129 | if q.y == 0: 130 | return p 131 | 132 | U1 = (p.x * q.z ** 2) % P 133 | U2 = (q.x * p.z ** 2) % P 134 | S1 = (p.y * q.z ** 3) % P 135 | S2 = (q.y * p.z ** 3) % P 136 | 137 | if U1 == U2: 138 | if S1 != S2: 139 | return Point(0, 0, 1) 140 | return cls._jacobianDouble(p, A, P) 141 | 142 | H = U2 - U1 143 | R = S2 - S1 144 | H2 = (H * H) % P 145 | H3 = (H * H2) % P 146 | U1H2 = (U1 * H2) % P 147 | nx = (R ** 2 - H3 - 2 * U1H2) % P 148 | ny = (R * (U1H2 - nx) - S1 * H3) % P 149 | nz = (H * p.z * q.z) % P 150 | 151 | return Point(nx, ny, nz) 152 | 153 | @classmethod 154 | def _jacobianMultiply(cls, p, n, N, A, P): 155 | """ 156 | Multily point and scalar in elliptic curves 157 | 158 | :param p: First Point to mutiply 159 | :param n: Scalar to mutiply 160 | :param N: Order of the elliptic curve 161 | :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) 162 | :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) 163 | :return: Point that represents the sum of First and Second Point 164 | """ 165 | if p.y == 0 or n == 0: 166 | return Point(0, 0, 1) 167 | 168 | if n == 1: 169 | return p 170 | 171 | if n < 0 or n >= N: 172 | return cls._jacobianMultiply(p, n % N, N, A, P) 173 | 174 | if (n % 2) == 0: 175 | return cls._jacobianDouble( 176 | cls._jacobianMultiply(p, n // 2, N, A, P), A, P 177 | ) 178 | 179 | return cls._jacobianAdd( 180 | cls._jacobianDouble(cls._jacobianMultiply(p, n // 2, N, A, P), A, P), p, A, P 181 | ) 182 | -------------------------------------------------------------------------------- /sha256/sha256.go: -------------------------------------------------------------------------------- 1 | // Implementation of SHA 256 in go based on https://en.wikipedia.org/wiki/SHA-2. 2 | package main 3 | 4 | import ( 5 | "bytes" 6 | "encoding/binary" 7 | "fmt" 8 | ) 9 | 10 | const ( 11 | h0 = uint32(0x6a09e667) 12 | h1 = uint32(0xbb67ae85) 13 | h2 = uint32(0x3c6ef372) 14 | h3 = uint32(0xa54ff53a) 15 | h4 = uint32(0x510e527f) 16 | h5 = uint32(0x9b05688c) 17 | h6 = uint32(0x1f83d9ab) 18 | h7 = uint32(0x5be0cd19) 19 | ) 20 | 21 | var k [64]uint32 = [64]uint32{ 22 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 23 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 24 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 25 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 26 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 27 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 28 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 29 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, 30 | } 31 | 32 | func check(err error) { 33 | if err != nil { 34 | panic(err) 35 | } 36 | } 37 | 38 | func rotateRight(in, k uint32) uint { 39 | return (uint(in) >> k) | (uint(in) << (32 - k)) 40 | } 41 | 42 | func preprocess(in string) []byte { 43 | lenIn := uint64(len(in) * 8) 44 | numZeros := (512 - (lenIn + 8 + 64)) / 8 45 | // fmt.Printf("numZeros=%d\n", numZeros) 46 | 47 | bytes := []byte(in) 48 | bytes = append(bytes, byte(0b10000000)) 49 | for i := 0; i < int(numZeros); i++ { 50 | bytes = append(bytes, byte(0b00)) 51 | } 52 | 53 | b := make([]byte, 8) 54 | binary.BigEndian.PutUint64(b, lenIn) 55 | // fmt.Printf("lenIN binary0=%b\n", b) 56 | for i := 0; i < 8; i++ { 57 | bytes = append(bytes, b[i]) 58 | } 59 | // fmt.Printf("lenIN binary1=%b\n", bytes[64-8:]) 60 | // fmt.Printf("*** preprocessed %v\n", bytes) 61 | // fmt.Printf("*** length %v\n", len(bytes)) 62 | return bytes 63 | } 64 | 65 | func sha256(in string) [32]byte { 66 | if len(in) > 64 { 67 | panic("message too long! only support messages < 64 characters") 68 | } 69 | preprocessed := preprocess(in) 70 | 71 | fmt.Printf("*** padded message=%x\n", preprocessed) 72 | // fmt.Printf("*** padded message=%08b\n", preprocessed) 73 | 74 | // First just use a single chunk. 75 | w := [64][4]byte{} 76 | 77 | // Copy in original message. 78 | for i := 0; i < 16; i++ { 79 | copy(w[i][:], preprocessed[4*i:4*(i+1)]) 80 | } 81 | 82 | tempArr := [64]uint32{} 83 | for i := 16; i < 64; i++ { 84 | var out0, out1, temp uint32 85 | buf := bytes.NewBuffer(w[i-7][:]) 86 | check(binary.Read(buf, binary.BigEndian, &out0)) 87 | buf = bytes.NewBuffer(w[i-16][:]) 88 | check(binary.Read(buf, binary.BigEndian, &out1)) 89 | 90 | buf = bytes.NewBuffer(w[i-15][:]) 91 | check(binary.Read(buf, binary.BigEndian, &temp)) 92 | s0 := rotateRight(temp, 7) ^ rotateRight(temp, 18) ^ uint(temp>>3) 93 | 94 | buf = bytes.NewBuffer(w[i-2][:]) 95 | check(binary.Read(buf, binary.BigEndian, &temp)) 96 | s1 := rotateRight(temp, 17) ^ rotateRight(temp, 19) ^ uint(temp>>10) 97 | // fmt.Printf("*** i-15: %d, w[i-15]: %d, s0: %d, s1: %d \n", i-15, w[i-15], s0, s1) 98 | // fmt.Printf("***** s0 + s1: %d \n", s0+s1) 99 | 100 | wIns := [4]byte{} 101 | binary.BigEndian.PutUint32(wIns[:], out0+uint32(s0)+out1+uint32(s1)) 102 | tempArr[i] = out0 + uint32(s0) + out1 + uint32(s1) 103 | 104 | if i == 16 { 105 | // buf = bytes.NewBuffer(w[i-2][:]) 106 | // check(binary.Read(buf, binary.BigEndian, &temp)) 107 | // fmt.Printf("*** first rotation of %d=%d\n", temp, rotateRight(temp, 17)) 108 | // fmt.Printf("*** term1=%d,term2=%d,term3=%d,term4=%d\n", s0, out0, s1, out1) 109 | // fmt.Printf("*** wIns: %x\n", wIns) 110 | // panic("here") 111 | } 112 | 113 | w[i] = wIns 114 | } 115 | fmt.Printf("*** message schedule=%x\n", w[:]) 116 | // var sInts []string 117 | // for _, i := range tempArr { 118 | // sInts = append(sInts, strconv.Itoa(int(i))) 119 | // } 120 | // fmt.Println(strings.Join(sInts, ", ")) 121 | 122 | a := h0 123 | b := h1 124 | c := h2 125 | d := h3 126 | e := h4 127 | f := h5 128 | g := h6 129 | h := h7 130 | 131 | for i := 0; i < 64; i++ { 132 | S1 := rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25) 133 | ch := (uint(e) & uint(f)) ^ (^uint(e) & uint(g)) 134 | 135 | wui32 := binary.BigEndian.Uint32(w[i][:]) 136 | temp1 := (uint(h) + S1 + ch + uint(k[i]) + uint(wui32)) % uint(1<<32) 137 | S0 := rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22) 138 | maj := (uint(a) & uint(b)) ^ (uint(a) & uint(c)) ^ (uint(b) & uint(c)) 139 | temp2 := (S0 + maj) % uint(1<<32) 140 | 141 | // if i == 0 { 142 | // fmt.Printf("*** e=%d\n", e) // 01010001000011100101001001111111 143 | // fmt.Printf("*** not e=%d\n", ^e) // 10101110111100011010110110000000 144 | // // (in >> k) | (in << (32 - k)) 145 | // fmt.Printf("*** shift e 6=%d\n", e>>6) 146 | // fmt.Printf("*** shift e left 26=%d\n", uint(e)<<26) 147 | // fmt.Printf("*** rot e 6=%d\n", rotateRight(e, 6)) 148 | // fmt.Printf("*** S1=%d\n", S1) 149 | // fmt.Printf("*** c1=%d\n", ch) 150 | // fmt.Printf("*** t1=%d\n", temp1) 151 | // fmt.Printf("*** t2=%d\n", temp2) 152 | // } 153 | // panic("here") 154 | h = g 155 | g = f 156 | f = e 157 | e = uint32((uint(d) + temp1) % uint(1<<32)) 158 | d = c 159 | c = b 160 | b = a 161 | a = uint32((temp1 + temp2) % uint(1<<32)) 162 | 163 | // if i == 0 { 164 | // fmt.Printf("*** a=%d\n", a) 165 | // fmt.Printf("*** b=%d\n", b) 166 | // fmt.Printf("*** c=%d\n", c) 167 | // fmt.Printf("*** d=%d\n", d) 168 | // fmt.Printf("*** e=%d\n", e) 169 | // fmt.Printf("*** f=%d\n", f) 170 | // fmt.Printf("*** g=%d\n", g) 171 | // fmt.Printf("*** h=%d\n", h) 172 | // } 173 | // panic("here") 174 | } 175 | 176 | h0out := uint32((uint(h0) + uint(a)) % uint(1<<32)) 177 | h1out := uint32((uint(h1) + uint(b)) % uint(1<<32)) 178 | h2out := uint32((uint(h2) + uint(c)) % uint(1<<32)) 179 | h3out := uint32((uint(h3) + uint(d)) % uint(1<<32)) 180 | h4out := uint32((uint(h4) + uint(e)) % uint(1<<32)) 181 | h5out := uint32((uint(h5) + uint(f)) % uint(1<<32)) 182 | h6out := uint32((uint(h6) + uint(g)) % uint(1<<32)) 183 | h7out := uint32((uint(h7) + uint(h)) % uint(1<<32)) 184 | 185 | // fmt.Printf("*** a=%d\n", a) 186 | fmt.Printf("*** h0out=%d\n", h0out) 187 | fmt.Printf("*** h1out=%d\n", h1out) 188 | fmt.Printf("*** h2out=%d\n", h2out) 189 | fmt.Printf("*** h3out=%d\n", h3out) 190 | fmt.Printf("*** h4out=%d\n", h4out) 191 | fmt.Printf("*** h5out=%d\n", h5out) 192 | fmt.Printf("*** h6out=%d\n", h6out) 193 | fmt.Printf("*** h7out=%d\n", h7out) 194 | 195 | out := [32]byte{} 196 | binary.BigEndian.PutUint32(out[:4], h0out) 197 | binary.BigEndian.PutUint32(out[4:8], h1out) 198 | binary.BigEndian.PutUint32(out[8:12], h2out) 199 | binary.BigEndian.PutUint32(out[12:16], h3out) 200 | binary.BigEndian.PutUint32(out[16:20], h4out) 201 | binary.BigEndian.PutUint32(out[20:24], h5out) 202 | binary.BigEndian.PutUint32(out[24:28], h6out) 203 | binary.BigEndian.PutUint32(out[28:32], h7out) 204 | return out 205 | } 206 | 207 | func main() { 208 | res := sha256("abc") 209 | fmt.Printf("%0x\n", res[:]) 210 | fmt.Printf("%d\n", res[:]) 211 | } 212 | -------------------------------------------------------------------------------- /sha256/sha256/src/main.nr: -------------------------------------------------------------------------------- 1 | // Rotate a u32 to the right by a variable amount. 2 | fn rotateRight32(input : u32, amount : u32) -> u32 { 3 | (input >> amount) + (input << (32-amount)) 4 | } 5 | 6 | fn s0(input : u32) -> u32 { 7 | rotateRight32(input, 7) ^ rotateRight32(input, 18) ^ (input >> 3) 8 | } 9 | 10 | fn s1(input : u32) -> u32 { 11 | rotateRight32(input, 17) ^ rotateRight32(input, 19) ^ (input >> 10) 12 | } 13 | 14 | fn S0(input : u32) -> u32 { 15 | rotateRight32(input, 2) ^ rotateRight32(input, 13) ^ rotateRight32(input, 22) 16 | } 17 | 18 | fn S1(input : u32) -> u32 { 19 | rotateRight32(input, 6) ^ rotateRight32(input, 11) ^ rotateRight32(input, 25) 20 | } 21 | 22 | fn ch(e : u32, f : u32, g : u32) -> u32 { 23 | (e & f) ^ (!e & g) 24 | } 25 | 26 | fn maj(a : u32, b : u32, c : u32) -> u32 { 27 | (a & b) ^ (a & c) ^ (b & c) 28 | } 29 | 30 | // Add padding to the input message. 31 | fn preprocess(input : [u8; 64], length : u8) -> [u8; 64] { 32 | let mut output = input; 33 | let numZeros : u8 = 64 - (length + 1 + 8); 34 | for i in 0..63 { 35 | let intI = i as u8; 36 | if intI < length { 37 | output[i] = input[i]; 38 | } 39 | if intI == length { 40 | output[i] = 128; 41 | } 42 | if intI > length & intI < length + numZeros { 43 | output[i] = 0; 44 | } 45 | }; 46 | output[63] = length * 8; 47 | output 48 | } 49 | 50 | fn createMessageSchedule(preprocessed : [u8; 64]) -> [u32; 64] { 51 | let mut output : [u32; 64] = [ 52 | 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 0, 0, 57 | 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 60 | ]; 61 | 62 | // Copy in original message. 63 | for i in 0..16 { 64 | // Shift and LAND bits of the u32 message chunk. 65 | let mut temp : u32 = preprocessed[4*i] as u32; 66 | let mut out = (temp << 24); 67 | temp = preprocessed[4*i+1] as u32; 68 | out = out + (temp << 16); 69 | temp = preprocessed[4*i+2] as u32; 70 | out = out + (temp << 8); 71 | temp = preprocessed[4*i+3] as u32; 72 | out = out + temp; 73 | output[i] = out; 74 | }; 75 | 76 | // Do the rotations. 77 | for i in 16..64 { 78 | let s0val = s0(output[i-15]); 79 | let s1val = s1(output[i-2]); 80 | output[i] = s0val + s1val + output[i-16] + output[i-7]; 81 | }; 82 | output 83 | } 84 | 85 | fn compress(input : [u32; 64]) -> [u8; 32] { 86 | let mut output : [u8; 32] = [ 87 | 0, 0, 0, 0, 0, 0, 0, 0, 88 | 0, 0, 0, 0, 0, 0, 0, 0, 89 | 0, 0, 0, 0, 0, 0, 0, 0, 90 | 0, 0, 0, 0, 0, 0, 0, 0, 91 | ]; 92 | 93 | // There are no array globals in noir yet. 94 | let k_arr : [u32; 64] = [ 95 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 96 | 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 97 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 98 | 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 99 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 100 | 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 101 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 102 | 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 103 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 104 | 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 105 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, 106 | ]; 107 | 108 | let mut h0: u32 = 0x6a09e667; 109 | let mut h1: u32 = 0xbb67ae85; 110 | let mut h2: u32 = 0x3c6ef372; 111 | let mut h3: u32 = 0xa54ff53a; 112 | let mut h4: u32 = 0x510e527f; 113 | let mut h5: u32 = 0x9b05688c; 114 | let mut h6: u32 = 0x1f83d9ab; 115 | let mut h7: u32 = 0x5be0cd19; 116 | 117 | let mut a = h0; 118 | let mut b = h1; 119 | let mut c = h2; 120 | let mut d = h3; 121 | let mut e = h4; 122 | let mut f = h5; 123 | let mut g = h6; 124 | let mut h = h7; 125 | 126 | for i in 0..63 { 127 | let S1Val = S1(e); 128 | let chVal = ch(e, f, g); 129 | let temp1 = h + S1Val + chVal + k_arr[i] + input[i]; 130 | 131 | let S0Val = S0(a); 132 | let majVal = maj(a, b, c); 133 | let temp2 = S0Val + majVal; 134 | 135 | h = g; 136 | g = f; 137 | f = e; 138 | e = d + temp1; 139 | d = c; 140 | c = b; 141 | b = a; 142 | a = temp1 + temp2; 143 | }; 144 | 145 | h0 = h0 + a; 146 | h1 = h1 + b; 147 | h2 = h2 + c; 148 | h3 = h3 + d; 149 | h4 = h4 + e; 150 | h5 = h5 + f; 151 | h6 = h6 + g; 152 | h7 = h7 + h; 153 | 154 | let hs = [h0, h1, h2, h3, h4, h5, h6, h7]; 155 | // Write the 32 bit words to the output array as 4, 8-bit ints. 156 | for i in 0..8 { 157 | let mut temp : u32 = hs[i]; 158 | output[4*i] = (temp >> 24) as u8; 159 | output[4*i+1] = (temp >> 16) as u8; 160 | output[4*i+2] = (temp >> 8) as u8; 161 | output[4*i+3] = temp as u8; 162 | }; 163 | output 164 | } 165 | 166 | 167 | fn main(input : pub [u8; 64], length : pub u8) { 168 | // Run preprocess padding. 169 | let preprocessed = preprocess(input, length); 170 | 171 | // Confirm that the preprocessed message is as expected. 172 | let expectedPreprocessed: [u8; 64] = [ 173 | 97, 98, 99, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 176 | ]; 177 | for i in 0..64 { 178 | constrain preprocessed[i] == expectedPreprocessed[i]; 179 | }; 180 | 181 | // Create the message schedule. 182 | let messageSchedule = createMessageSchedule(preprocessed); 183 | 184 | // Confirm that the message schedule is as expected. 185 | let expectedSchedule: [u32; 64] = [ 186 | 1633837952, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 1633837952, 187 | 983040, 2108187653, 1610613702, 1050508152, 25426944, 316456923, 188 | 3806512014, 3357629466, 3073800610, 3854317833, 845560923, 2636160359, 189 | 3968280267, 1881225380, 3552024379, 2482346367, 996719219, 2952069057, 190 | 4043988066, 176896406, 1924104970, 2483675966, 610538786, 2672279444, 191 | 4037431130, 1042573945, 657669027, 206005234, 2215296807, 2049510749, 192 | 106709978, 4215179723, 3430291419, 3118885940, 2845390439, 2226839261, 193 | 3256115900, 344409900, 2987358873, 4015503821, 3957764664, 2682456414, 194 | 2025622859, 2755645205, 1720397816, 4004225740, 313650667, 195 | ]; 196 | for i in 0..64 { 197 | constrain messageSchedule[i] == expectedSchedule[i]; 198 | }; 199 | 200 | // Compress the message into the output. 201 | let compressedMessage = compress(messageSchedule); 202 | 203 | // Confirm that the output is as expected. 204 | // SHA256("abc") = 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 205 | let expectedCompressed: [u8; 32] = [ 206 | 186, 120, 22, 191, 143, 1, 207, 234, 65, 65, 64, 222, 93, 174, 34, 35, 207 | 176, 3, 97, 163, 150, 23, 122, 156, 180, 16, 255, 97, 242, 0, 21, 173, 208 | ]; 209 | for i in 0..32 { 210 | constrain compressedMessage[i] == expectedCompressed[i]; 211 | }; 212 | } -------------------------------------------------------------------------------- /sha256/sha256.py: -------------------------------------------------------------------------------- 1 | """This Python module is an implementation of the SHA-256 algorithm. 2 | From https://github.com/keanemind/Python-SHA-256""" 3 | 4 | K = [ 5 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 6 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 7 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 8 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 9 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 10 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 11 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 12 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 13 | ] 14 | 15 | def stringFromArr(arr): 16 | out = [] 17 | for el in arr: 18 | out.append(el.hex()) 19 | return out 20 | 21 | def generate_hash(message: bytearray) -> bytearray: 22 | """Return a SHA-256 hash from the message passed. 23 | The argument should be a bytes, bytearray, or 24 | string object.""" 25 | 26 | if isinstance(message, str): 27 | message = bytearray(message, 'ascii') 28 | elif isinstance(message, bytes): 29 | message = bytearray(message) 30 | elif not isinstance(message, bytearray): 31 | raise TypeError 32 | 33 | # Padding 34 | length = len(message) * 8 # len(message) is number of BYTES!!! 35 | message.append(0x80) 36 | while (len(message) * 8 + 64) % 512 != 0: 37 | message.append(0x00) 38 | 39 | message += length.to_bytes(8, 'big') # pad to 8 bytes or 64 bits 40 | 41 | # print("*** padded message={}".format(message.hex())) 42 | 43 | assert (len(message) * 8) % 512 == 0, "Padding did not complete properly!" 44 | 45 | # Parsing 46 | blocks = [] # contains 512-bit chunks of message 47 | for i in range(0, len(message), 64): # 64 bytes is 512 bits 48 | blocks.append(message[i:i+64]) 49 | 50 | # Setting Initial Hash Value 51 | h0 = 0x6a09e667 52 | h1 = 0xbb67ae85 53 | h2 = 0x3c6ef372 54 | h3 = 0xa54ff53a 55 | h5 = 0x9b05688c 56 | h4 = 0x510e527f 57 | h6 = 0x1f83d9ab 58 | h7 = 0x5be0cd19 59 | 60 | # SHA-256 Hash Computation 61 | for message_block in blocks: 62 | # Prepare message schedule 63 | message_schedule = [] 64 | for t in range(0, 64): 65 | if t <= 15: 66 | # adds the t'th 32 bit word of the block, 67 | # starting from leftmost word 68 | # 4 bytes at a time 69 | message_schedule.append(bytes(message_block[t*4:(t*4)+4])) 70 | else: 71 | term3 = _sigma1(int.from_bytes(message_schedule[t-2], 'big')) 72 | term2 = int.from_bytes(message_schedule[t-7], 'big') 73 | term1 = _sigma0(int.from_bytes(message_schedule[t-15], 'big')) 74 | term4 = int.from_bytes(message_schedule[t-16], 'big') 75 | 76 | # if t == 17: 77 | # temp = int.from_bytes(message_schedule[t-2], 'big') 78 | # print("*** first rotation of {}={}\n".format(temp, _rotate_right(temp, 17))) 79 | # print("*** term1={},term2={},term3={},term4={}".format(term1, term2, term3, term4)) 80 | 81 | # append a 4-byte byte object 82 | schedule = ((term1 + term2 + term3 + term4) % 2**32).to_bytes(4, 'big') 83 | message_schedule.append(schedule) 84 | 85 | assert len(message_schedule) == 64 86 | # print("*** message schedule={}".format(stringFromArr(message_schedule))) 87 | 88 | # Initialize working variables 89 | a = h0 90 | b = h1 91 | c = h2 92 | d = h3 93 | e = h4 94 | f = h5 95 | g = h6 96 | h = h7 97 | 98 | # Iterate for t=0 to 63 99 | for t in range(64): 100 | t1 = ((h + _capsigma1(e) + _ch(e, f, g) + K[t] + 101 | int.from_bytes(message_schedule[t], 'big')) % 2**32) 102 | 103 | t2 = (_capsigma0(a) + _maj(a, b, c)) % 2**32 104 | 105 | # if t == 63: 106 | # print("*** e={}".format(e)) 107 | # (num >> shift) | (num << (size - shift)) 108 | # print("*** shift e 6={}".format(e >> 6)) 109 | # print("*** shift e left 26={}".format(e << 26)) 110 | # print("*** rot e 6={}".format(_rotate_right(e, 6))) 111 | # print("*** S1={}".format(_capsigma1(e))) 112 | # print("*** ch={}".format(_ch(e, f, g))) 113 | # print("*** t1={}".format(t1)) 114 | # print("*** t2={}".format(t2)) 115 | 116 | h = g 117 | g = f 118 | f = e 119 | e = (d + t1) % 2**32 120 | d = c 121 | c = b 122 | b = a 123 | a = (t1 + t2) % 2**32 124 | 125 | 126 | # Compute intermediate hash value 127 | h0 = (h0 + a) % 2**32 128 | h1 = (h1 + b) % 2**32 129 | h2 = (h2 + c) % 2**32 130 | h3 = (h3 + d) % 2**32 131 | h4 = (h4 + e) % 2**32 132 | h5 = (h5 + f) % 2**32 133 | h6 = (h6 + g) % 2**32 134 | h7 = (h7 + h) % 2**32 135 | 136 | # print("*** a={}".format(a)) 137 | # print("*** h0out={}".format(h0)) 138 | # print("*** h1out={}".format(h1)) 139 | # print("*** h2out={}".format(h2)) 140 | # print("*** h3out={}".format(h3)) 141 | # print("*** h4out={}".format(h4)) 142 | # print("*** h5out={}".format(h5)) 143 | # print("*** h6out={}".format(h6)) 144 | # print("*** h7out={}".format(h7)) 145 | 146 | 147 | # temp = (h0).to_bytes(4, 'big') 148 | # print("*** h0bytes={}".format(temp.hex())) 149 | 150 | 151 | return ((h0).to_bytes(4, 'big') + (h1).to_bytes(4, 'big') + 152 | (h2).to_bytes(4, 'big') + (h3).to_bytes(4, 'big') + 153 | (h4).to_bytes(4, 'big') + (h5).to_bytes(4, 'big') + 154 | (h6).to_bytes(4, 'big') + (h7).to_bytes(4, 'big')) 155 | 156 | def _sigma0(num: int): 157 | """As defined in the specification.""" 158 | num = (_rotate_right(num, 7) ^ 159 | _rotate_right(num, 18) ^ 160 | (num >> 3)) 161 | return num 162 | 163 | def _sigma1(num: int): 164 | """As defined in the specification.""" 165 | num = (_rotate_right(num, 17) ^ 166 | _rotate_right(num, 19) ^ 167 | (num >> 10)) 168 | return num 169 | 170 | def _capsigma0(num: int): 171 | """As defined in the specification.""" 172 | num = (_rotate_right(num, 2) ^ 173 | _rotate_right(num, 13) ^ 174 | _rotate_right(num, 22)) 175 | return num 176 | 177 | def _capsigma1(num: int): 178 | """As defined in the specification.""" 179 | num = (_rotate_right(num, 6) ^ 180 | _rotate_right(num, 11) ^ 181 | _rotate_right(num, 25)) 182 | return num 183 | 184 | def _ch(x: int, y: int, z: int): 185 | """As defined in the specification.""" 186 | return (x & y) ^ (~x & z) 187 | 188 | def _maj(x: int, y: int, z: int): 189 | """As defined in the specification.""" 190 | return (x & y) ^ (x & z) ^ (y & z) 191 | 192 | def _rotate_right(num: int, shift: int, size: int = 32): 193 | """Rotate an integer right.""" 194 | return (num >> shift) | (num << (size - shift)) 195 | 196 | if __name__ == "__main__": 197 | # generate_hash("abc").hex() 198 | print(generate_hash("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz").hex()) 199 | -------------------------------------------------------------------------------- /ecdsa/src/bigint/arithmetic.nr: -------------------------------------------------------------------------------- 1 | global U64_LOWER_32_BITS : u64 = 4294967295; 2 | global U64_UPPER_32_BITS : u64 = 18446744069414584320; 3 | global U64_POW_2_32 : u64 = 4294967296; 4 | 5 | // returns sum = a + b + carry, and the new carry. 6 | fn add_limbs_with_carry(a: u32, b: u32, carry: u32) -> (u32, u32) { 7 | let sum : u64 = a as u64 + b as u64 + carry as u64; 8 | let new_carry : u32 = ((sum & U64_UPPER_32_BITS) / U64_POW_2_32) as u32; 9 | ((sum & U64_LOWER_32_BITS) as u32, new_carry) 10 | } 11 | 12 | // Returns diff = a - b - borrow, and the new borrow. 13 | fn sub_limbs_with_borrow(a: u32, b: u32, borrow: u32) -> (u32, u32) { 14 | let diff_with_overflow : u64 = (U64_POW_2_32 as u64) + (a as u64) - (b as u64) - (borrow as u64); 15 | let diff = diff_with_overflow & U64_LOWER_32_BITS; 16 | if diff_with_overflow < U64_POW_2_32 { 17 | // Borrow was necessary 18 | ((diff & U64_LOWER_32_BITS) as u32, 1 as u32) 19 | } else { 20 | ((diff & U64_LOWER_32_BITS) as u32, 0 as u32) 21 | } 22 | } 23 | 24 | // TODO: Tests for max b and 0 b 25 | // Returns diff = a - (b * c) - borrow, and the new borrow. 26 | fn sub_mul_limbs_with_borrow(a: u32, b: u32, c: u32, borrow: u32) -> (u32, u32) { 27 | let diff_with_overflow : u64 = (U64_UPPER_32_BITS as u64) + (a as u64) - (b as u64 * c as u64) - (borrow as u64); 28 | let diff = diff_with_overflow & U64_LOWER_32_BITS; 29 | let new_borrow = ((U64_UPPER_32_BITS - (diff_with_overflow & U64_UPPER_32_BITS)) / U64_POW_2_32) as u32; 30 | ((diff & U64_LOWER_32_BITS) as u32, new_borrow) 31 | } 32 | 33 | // 9999 - (9 * 99) 34 | 35 | // borrow = 0 36 | // 9 - 9 * 9 - 0 37 | // 99 - 09 * 09 - 0 = 18 38 | // diff = 8 39 | // borrow = 9 - 1 = 8 40 | 41 | // borrow = 8 42 | // 9 - 9 * 9 - 8 43 | // 99 - 09 * 09 - 8 = 10 44 | // diff = 0 45 | // borrow = 9 - 1 = 8 46 | 47 | // borrow = 8 48 | // 9 - 9 * 0 - 8 49 | // 99 - 09 * 0 - 8 = 91 50 | // diff = 1 51 | // borrow = 9 - 9 = 0 52 | 53 | // borrow = 0 54 | // 9 - 9 * 0 - 0 55 | // 99 - 09 * 0 - 0 = 99 56 | // diff = 9 57 | // borrow = 9 - 9 = 0 58 | 59 | // Result: 9108 60 | 61 | 62 | 63 | // returns a + (b * c) + carry, and the new carry. 64 | fn mul_limbs_with_carry(a: u32, b: u32, c: u32, carry: u32) -> (u32, u32) { 65 | let calc_result : u64 = a as u64 + (b as u64 * c as u64) + carry as u64; 66 | let new_carry : u32 = ((calc_result & U64_UPPER_32_BITS) / U64_POW_2_32) as u32; 67 | ((calc_result & U64_LOWER_32_BITS) as u32, new_carry) 68 | } 69 | 70 | 71 | // Tests 72 | fn run_tests() { 73 | test_add_limbs(); 74 | test_sub_limbs(); 75 | test_mul_limbs(); 76 | } 77 | 78 | // add_limbs_with_carry 79 | fn test_add_limbs_with_carry_case1() { 80 | let a = 1; 81 | let b = 4294967295; // 2^32 - 1 82 | let expected_sum = 0; 83 | let expected_new_carry = 1; 84 | let (sum, new_carry) = add_limbs_with_carry(a, b, 0); 85 | constrain sum == expected_sum; 86 | constrain new_carry == expected_new_carry; 87 | } 88 | 89 | fn test_add_limbs_with_carry_case2() { 90 | let a = 99; 91 | let b = 4294967295; // 2^32 - 1 92 | let expected_sum = 98; 93 | let expected_new_carry = 1; 94 | let (sum, new_carry) = add_limbs_with_carry(a, b, 0); 95 | constrain sum == expected_sum; 96 | constrain new_carry == expected_new_carry; 97 | } 98 | 99 | fn test_add_limbs_with_carry_case3() { 100 | let a = 5; 101 | let b = 10; 102 | let carry = 7; 103 | let expected_sum = 22; 104 | let expected_new_carry = 0; 105 | let (sum, new_carry) = add_limbs_with_carry(a, b, carry); 106 | constrain sum == expected_sum; 107 | constrain new_carry == expected_new_carry; 108 | } 109 | 110 | fn test_add_limbs_with_carry_case4() { 111 | let a = 4294967295; // 2^32 - 1 112 | let b = 0; 113 | let carry = 1; 114 | let expected_sum = 0; 115 | let expected_new_carry = 1; 116 | let (sum, new_carry) = add_limbs_with_carry(a, b, carry); 117 | constrain sum == expected_sum; 118 | constrain new_carry == expected_new_carry; 119 | } 120 | 121 | fn test_add_limbs() { 122 | test_add_limbs_with_carry_case1(); 123 | test_add_limbs_with_carry_case2(); 124 | test_add_limbs_with_carry_case3(); 125 | test_add_limbs_with_carry_case4(); 126 | } 127 | 128 | //sub_limbs_with_borrow 129 | fn test_sub_limbs_with_borrow_case1() { 130 | let a = 5; 131 | let b = 3; 132 | let expected_diff = 2; 133 | let expected_new_borrow = 0; 134 | let (diff, new_borrow) = sub_limbs_with_borrow(a, b, 0); 135 | constrain diff == expected_diff; 136 | constrain new_borrow == expected_new_borrow; 137 | } 138 | 139 | fn test_sub_limbs_with_borrow_case2() { 140 | let a = 0; 141 | let b = 1; 142 | let expected_diff = (U64_POW_2_32 - 1) as u32; 143 | let expected_new_borrow = 1; 144 | let (diff, new_borrow) = sub_limbs_with_borrow(a, b, 0); 145 | constrain diff == expected_diff; 146 | constrain new_borrow == expected_new_borrow; 147 | } 148 | 149 | fn test_sub_limbs_with_borrow_case3() { 150 | let a = 0; 151 | let b = 1; 152 | let borrow = 1; 153 | let expected_diff = (U64_POW_2_32 - 2) as u32; 154 | let expected_new_borrow = 1; 155 | let (diff, new_borrow) = sub_limbs_with_borrow(a, b, borrow); 156 | constrain diff == expected_diff; 157 | constrain new_borrow == expected_new_borrow; 158 | } 159 | 160 | fn test_sub_limbs_with_borrow_case4() { 161 | let a = 1000; 162 | let b = 44; 163 | let borrow = 1; 164 | let expected_diff = 955; 165 | let expected_new_borrow = 0; 166 | let (diff, new_borrow) = sub_limbs_with_borrow(a, b, borrow); 167 | constrain diff == expected_diff; 168 | constrain new_borrow == expected_new_borrow; 169 | } 170 | 171 | fn test_sub_limbs_with_borrow_case5() { 172 | let a = (U64_POW_2_32 - 1) as u32; 173 | let b = (U64_POW_2_32 - 1) as u32; 174 | let borrow = 1; 175 | let expected_diff = (U64_POW_2_32 - 1) as u32; 176 | let expected_new_borrow = 1; 177 | let (diff, new_borrow) = sub_limbs_with_borrow(a, b, borrow); 178 | constrain diff == expected_diff; 179 | constrain new_borrow == expected_new_borrow; 180 | } 181 | 182 | fn test_sub_limbs() { 183 | test_sub_limbs_with_borrow_case1(); 184 | test_sub_limbs_with_borrow_case2(); 185 | test_sub_limbs_with_borrow_case3(); 186 | test_sub_limbs_with_borrow_case4(); 187 | test_sub_limbs_with_borrow_case5(); 188 | } 189 | 190 | // mul_limbs_with_carry 191 | fn test_mul_limbs_with_carry_case1() { 192 | let a = 75; 193 | let b = 9; 194 | let c = 11; 195 | let carry = 7; 196 | let expected_product = 181; 197 | let expected_new_carry = 0; 198 | let (product, new_carry) = mul_limbs_with_carry(a, b, c, carry); 199 | constrain product == expected_product; 200 | constrain new_carry == expected_new_carry; 201 | } 202 | 203 | fn test_mul_limbs_with_carry_case2() { 204 | let a = 0; 205 | let b = 4294967295; // 2^32 - 1 206 | let c = 4294967295; // 2^32 - 1 207 | let carry = 0; 208 | let expected_product = 1; 209 | let expected_new_carry = 4294967294; // 2^32 - 2 210 | let (product, new_carry) = mul_limbs_with_carry(a, b, c, carry); 211 | constrain product == expected_product; 212 | constrain new_carry == expected_new_carry; 213 | } 214 | 215 | fn test_mul_limbs_with_carry_case3() { 216 | let a = 0; 217 | let b = 4294967295; // 2^32 - 1 218 | let c = 4294967295; // 2^32 - 1 219 | let carry = 4294967295; // 2^32 - 1 220 | let expected_product = 0; 221 | let expected_new_carry = 4294967295; // 2^32 - 1 222 | let (product, new_carry) = mul_limbs_with_carry(a, b, c, carry); 223 | constrain product == expected_product; 224 | constrain new_carry == expected_new_carry; 225 | } 226 | 227 | fn test_mul_limbs() { 228 | test_mul_limbs_with_carry_case1(); 229 | test_mul_limbs_with_carry_case2(); 230 | test_mul_limbs_with_carry_case3(); 231 | } 232 | -------------------------------------------------------------------------------- /ecdsa/src/main.nr: -------------------------------------------------------------------------------- 1 | mod bigint; 2 | 3 | use dep::std; 4 | mod u32_utils; 5 | mod arithmetic; 6 | mod division; 7 | 8 | global NUM_LIMBS : Field = 8; 9 | global LIMB_BITS : Field = 32; 10 | global LIMB_BYTES : Field = 4; 11 | 12 | global DOUBLE_LIMBS : Field = 16; 13 | 14 | // This defines a BigInt, a smart wrapper around a sequence of u32 limbs, least-significant limb first 15 | struct BigInt { 16 | limbs : [u32; NUM_LIMBS], 17 | } 18 | 19 | // TODO: impl 20 | struct BigInt2 { 21 | limbs : [u32; DOUBLE_LIMBS], 22 | } 23 | 24 | // TODO: This is a temporary solution that we are using because a struct inside of a tuple doesn't work 25 | // https://github.com/noir-lang/noir/issues/492 26 | struct LimbsWithOverflow { 27 | limbs : [u32; NUM_LIMBS], 28 | overflow: u32, 29 | } 30 | 31 | impl BigInt { 32 | /// Creation 33 | 34 | // Creates and initializes a BigInt. 35 | fn new(limbs : [u32; NUM_LIMBS]) -> Self { 36 | Self { 37 | limbs: limbs 38 | } 39 | } 40 | 41 | // Returns the additive identity element 42 | fn zero() -> Self { 43 | BigInt::new([0 as u32; NUM_LIMBS]) 44 | } 45 | 46 | // Returns the multiplicative identity element 47 | fn one() -> Self { 48 | let mut one = [0 as u32; NUM_LIMBS]; 49 | one[0] = 1; 50 | BigInt::new(one) 51 | } 52 | 53 | // Returns the big integer representation of a given little endian byte array 54 | fn from_bytes_le(bytes : [u8]) -> Self { 55 | // The maximum number of bytes that can fit in this bigint 56 | let MAX_BYTES : comptime Field = NUM_LIMBS * LIMB_BYTES; 57 | let SHIFTS : [comptime u32; 4] = [ 58 | u32_utils::U32_POW_2_0, 59 | u32_utils::U32_POW_2_8, 60 | u32_utils::U32_POW_2_16, 61 | u32_utils::U32_POW_2_24, 62 | ]; 63 | 64 | let bytes_len = std::array::len(bytes) as u32; 65 | 66 | // TODO: Should we allow this? 67 | constrain bytes_len <= MAX_BYTES as u32; 68 | 69 | let mut limbs = [0 as u32; NUM_LIMBS]; 70 | let mut limb : u32 = 0; 71 | for i in 0..MAX_BYTES { 72 | let limb_index = ((i as u8) / 4) as Field; 73 | // i modulo 4 74 | let byte_significance = i - (limb_index * 4); 75 | 76 | if i as u32 < bytes_len { 77 | let mut byte : u32 = bytes[i] as u32; 78 | byte = byte * SHIFTS[byte_significance]; 79 | limb = limb | byte; 80 | } 81 | if byte_significance == 3 { 82 | limbs[limb_index] = limb; 83 | limb = 0; 84 | } 85 | }; 86 | // constrain limbs[0] == 1; 87 | BigInt::new(limbs) 88 | } 89 | 90 | /// Math 91 | 92 | // Returns last non-zero limb, its index, and the limb before it as tuple (msl_index, msl_minus_one, msl). 93 | // Fails if most_significant_limb index < 1. 94 | fn two_most_significant_limbs(self : Self) -> (u32, u32, u32) { 95 | let mut msl_index = 0 as u32; 96 | let mut msl = 0 as u32; 97 | let mut msl_minus_one = 0 as u32; 98 | for i in 0..NUM_LIMBS { 99 | let j = NUM_LIMBS - i - 1; 100 | if (self.limbs[j] > 0) & (msl == 0) { 101 | msl_index = j as u32; 102 | msl = self.limbs[j]; 103 | msl_minus_one = self.limbs[j - 1]; 104 | } 105 | }; 106 | constrain msl_index >= 1; 107 | (msl_index, msl_minus_one, msl) 108 | } 109 | 110 | // Returns last non-zero limb, its index, and the 2 limbs before it as tuple (msl_index, msl_minus_two, msl_minus_one, msl). 111 | // Fails if most_significant_limb index < 2. 112 | fn three_most_significant_limbs(self : Self) -> (u32, u32, u32, u32) { 113 | let mut msl_index = 0 as u32; 114 | let mut msl = 0 as u32; 115 | let mut msl_minus_one = 0 as u32; 116 | let mut msl_minus_two = 0 as u32; 117 | for i in 0..NUM_LIMBS { 118 | let j = NUM_LIMBS - i - 1; 119 | if (self.limbs[j] > 0) & (msl == 0) { 120 | msl_index = j as u32; 121 | msl = self.limbs[j]; 122 | msl_minus_one = self.limbs[j - 1]; 123 | msl_minus_two = self.limbs[j - 2]; 124 | } 125 | }; 126 | constrain msl_index >= 2; 127 | (msl_index, msl_minus_two, msl_minus_one, msl) 128 | } 129 | 130 | // Returns self ^ exponent. 131 | // fn pow(self : Self, exponent : u32) -> Self { 132 | // if self.is_one() | exponent == 0 { 133 | // BigInt::one(); 134 | // } else { 135 | // if self.is_zero() { 136 | // BigInt::zero(); 137 | // } else { 138 | // 139 | // } 140 | // } 141 | // 142 | // } 143 | 144 | // Returns (self ^ exponent) % modulus. 145 | // fn pow_mod(self : Self, exponent : u32, modulus : Self) 146 | 147 | fn add(self : Self, other : BigInt) -> LimbsWithOverflow { 148 | let mut limbs : [u32; NUM_LIMBS] = [0 as u32; NUM_LIMBS]; 149 | let mut carry : u32 = 0; 150 | for i in 0..NUM_LIMBS { 151 | let (limb_sum, new_carry) = arithmetic::add_limbs_with_carry(self.limbs[i], other.limbs[i], carry); 152 | limbs[i] = limb_sum; 153 | carry = new_carry; 154 | }; 155 | LimbsWithOverflow { 156 | limbs: limbs, 157 | overflow: carry, 158 | } 159 | } 160 | 161 | fn mul(self : Self, other : BigInt) -> BigInt2 { 162 | // Double limbs won't overflow because the product of two N-limb arrays is never larger than 2N-limbs 163 | // ((b^n) - 1) * ((b^n) - 1) = b^(2n) - 2(b^n) - 1 < b^(2n) 164 | let mut limbs = [0 as u32; DOUBLE_LIMBS]; 165 | 166 | for i in 0..NUM_LIMBS { 167 | let mut carry : u32 = 0; 168 | for j in 0..NUM_LIMBS { 169 | let k = i + j; 170 | let (limb_product, new_carry) = arithmetic::mul_limbs_with_carry(limbs[k], self.limbs[i], other.limbs[j], carry); 171 | limbs[k] = limb_product; 172 | carry = new_carry; 173 | }; 174 | limbs[i + NUM_LIMBS] = carry; 175 | }; 176 | 177 | BigInt2 { 178 | limbs: limbs, 179 | } 180 | } 181 | 182 | // Returns self + other % modulus. 183 | // fn add_mod(self : Self, other : Self, modulus : Self) 184 | 185 | // Returns self * other % modulus. 186 | // fn mul_mod(self : Self, other : Self, modulus : Self) 187 | 188 | // Returns self - other. 189 | fn sub(self : Self, other : Self) -> LimbsWithOverflow { 190 | let mut limbs : [u32; NUM_LIMBS] = [0 as u32; NUM_LIMBS]; 191 | let mut borrow : u32 = 0; 192 | for i in 0..NUM_LIMBS { 193 | let (limb_diff, new_borrow) = arithmetic::sub_limbs_with_borrow(self.limbs[i], other.limbs[i], borrow); 194 | limbs[i] = limb_diff; 195 | borrow = new_borrow; 196 | }; 197 | 198 | // ToDo: This is a work around because structs in tuples don't work 199 | LimbsWithOverflow { 200 | limbs: limbs, 201 | overflow: borrow, 202 | } 203 | } 204 | 205 | // Returns self - (multiplicand * other). 206 | fn sub_mul(self : Self, multiplicand : u32, other : BigInt) -> LimbsWithOverflow { 207 | let mut limbs : [u32; NUM_LIMBS] = [0 as u32; NUM_LIMBS]; 208 | let mut borrow : u32 = 0; 209 | for i in 0..NUM_LIMBS { 210 | let (limb_diff, new_borrow) = arithmetic::sub_mul_limbs_with_borrow(self.limbs[i], multiplicand, other.limbs[i], borrow); 211 | limbs[i] = limb_diff; 212 | borrow = new_borrow; 213 | }; 214 | 215 | // ToDo: This is a work around because structs in tuples don't work 216 | LimbsWithOverflow { 217 | limbs: limbs, 218 | overflow: borrow, 219 | } 220 | } 221 | 222 | // Returns true iff this number is even. 223 | fn is_even(self : Self) -> bool { 224 | self.limbs[0] % 2 == 0 225 | } 226 | 227 | // Returns true iff this number is odd. 228 | fn is_odd(self : Self) -> bool { 229 | self.limbs[0] % 2 == 1 230 | } 231 | 232 | // Returns true iff all limbs are zero. 233 | fn is_zero(self : Self) -> bool { 234 | let mut result : bool = self.limbs[0] == 0; 235 | for i in 1..NUM_LIMBS { 236 | if result == true { 237 | result = self.limbs[i] == 0; 238 | } 239 | }; 240 | result 241 | } 242 | 243 | // Returns true iff this number is one. 244 | fn is_one(self : Self) -> bool { 245 | let mut result : bool = self.limbs[0] == 1; 246 | for i in 1..NUM_LIMBS { 247 | if result == true { 248 | result = self.limbs[i] == 0; 249 | } 250 | }; 251 | result 252 | } 253 | } 254 | 255 | // /// Excerpted from https://docs.rs/num-bigint/latest/src/num_bigint/biguint/division.rs.html#210 256 | // /// An implementation of the base division algorithm. 257 | // /// Knuth, TAOCP vol 2 section 4.3.1, algorithm D, with an improvement from exercises 19-21. 258 | fn div_rem_core(mut a: BigInt, b: BigInt) -> BigInt { 259 | // TODO: debug_assert!(a.data.len() >= b.len() && b.len() > 1); 260 | // TODO: debug_assert!(b.last().unwrap().leading_zeros() == 0); 261 | 262 | // The algorithm works by incrementally calculating "guesses", q0, for the next digit of the 263 | // quotient. Once we have any number q0 such that (q0 << j) * b <= a, we can set 264 | // 265 | // q += q0 << j 266 | // a -= (q0 << j) * b 267 | // 268 | // and then iterate until a < b. Then, (q, a) will be our desired quotient and remainder. 269 | // 270 | // q0, our guess, is calculated by dividing the last three digits of a by the last two digits of 271 | // b - this will give us a guess that is close to the actual quotient, but is possibly greater. 272 | // It can only be greater by 1 and only in rare cases, with probability at most 273 | // 2^-(big_digit::BITS-1) for random a, see TAOCP 4.3.1 exercise 21. 274 | // 275 | // If the quotient turns out to be too large, we adjust it by 1: 276 | // q -= 1 << j 277 | // a += b << j 278 | 279 | // a0 stores an additional extra most significant digit of the dividend, not stored in a. 280 | let mut a0 = 0 as u32; 281 | let (mut a_msl_index, mut a2, mut a1) = a.two_most_significant_limbs(); 282 | 283 | // [b1, b0] are the two most significant digits of the divisor. They never change. 284 | let (b_msl_index, b1, b0) = b.two_most_significant_limbs(); 285 | 286 | let q_len = a_msl_index - b_msl_index + 1; 287 | let mut q_limbs = [0 as u32; NUM_LIMBS]; 288 | 289 | // TODO: REMOVE 290 | constrain q_limbs[0] == 0; 291 | 292 | for i in 0..NUM_LIMBS { 293 | let j = NUM_LIMBS - i; 294 | if j as u32 < q_len { 295 | // TODO: debug_assert!(a.data.len() == b.len() + j); 296 | // The first q_estimate is [a2,a1,a0] / [b1,b0]. It will never be too small, it may be too large 297 | // by at most 1. 298 | let mut q_estimate = 0 as u32; 299 | let mut r = 0 as u64; 300 | if a0 < b0 { 301 | let result = division::div_wide(a0, a1, a2, b0, b1); 302 | q_estimate = result.0; 303 | r = result.1; 304 | } else { 305 | // TODO: debug_assert!(a0 == b0); 306 | // Avoid overflowing q_estimate 307 | // [a1,a0] = b0 * (1< 0 { 319 | // q_estimate is too large. We need to add back one multiple of b. 320 | q_estimate = q_estimate - 1; 321 | let add_result = a.add(b); 322 | a = BigInt::new(add_result.limbs); 323 | borrow = borrow - add_result.overflow; 324 | } 325 | // The top digit of a, stored in a0, has now been zeroed. 326 | // TODO: debug_assert!(borrow == a0); 327 | 328 | q_limbs[j] = q_estimate; 329 | 330 | // Don't do this on the last iteration when the quotient is fully formed 331 | if j != 0 { 332 | let (a_msl_index_update, a2_update, a1_update, a0_update) = a.three_most_significant_limbs(); 333 | a_msl_index = a_msl_index_update; 334 | a0 = a0_update; 335 | a1 = a1_update; 336 | a2 = a2_update; 337 | } 338 | } 339 | }; 340 | // (BigInt::new(q_limbs), a) 341 | BigInt::new(q_limbs) 342 | } 343 | 344 | fn main(x : [u32; bigint::NUM_LIMBS], y : [u32; bigint::NUM_LIMBS]) { 345 | constrain x == y; 346 | let x_as_bigint = BigInt::new(x); 347 | let y_as_bigint = BigInt::new(y); 348 | let product = x_as_bigint.mul(y_as_bigint); 349 | let expected_product_limbs = [1 as u32, 0, 0, 0, 0, 0, 0, 0, 4294967294, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295]; 350 | constrain product.limbs == expected_product_limbs; 351 | // bigint::run_tests(); 352 | } -------------------------------------------------------------------------------- /ecdsa/src/bigint.nr: -------------------------------------------------------------------------------- 1 | use dep::std; 2 | mod u32_utils; 3 | mod arithmetic; 4 | mod division; 5 | 6 | global NUM_LIMBS : Field = 8; 7 | global LIMB_BITS : Field = 32; 8 | global LIMB_BYTES : Field = 4; 9 | 10 | global DOUBLE_LIMBS : Field = 16; 11 | 12 | // This defines a BigInt, a smart wrapper around a sequence of u32 limbs, least-significant limb first 13 | struct BigInt { 14 | limbs : [u32; NUM_LIMBS], 15 | } 16 | 17 | // TODO: impl 18 | struct BigInt2 { 19 | limbs : [u32; DOUBLE_LIMBS], 20 | } 21 | 22 | // TODO: This is a temporary solution that we are using because a struct inside of a tuple doesn't work 23 | // https://github.com/noir-lang/noir/issues/492 24 | struct LimbsWithOverflow { 25 | limbs : [u32; NUM_LIMBS], 26 | overflow: u32, 27 | } 28 | 29 | impl BigInt { 30 | /// Creation 31 | 32 | // Creates and initializes a BigInt. 33 | fn new(limbs : [u32; NUM_LIMBS]) -> Self { 34 | Self { 35 | limbs: limbs 36 | } 37 | } 38 | 39 | // Returns the additive identity element 40 | fn zero() -> Self { 41 | BigInt::new([0 as u32; NUM_LIMBS]) 42 | } 43 | 44 | // Returns the multiplicative identity element 45 | fn one() -> Self { 46 | let mut one = [0 as u32; NUM_LIMBS]; 47 | one[0] = 1; 48 | BigInt::new(one) 49 | } 50 | 51 | // Returns the big integer representation of a given little endian byte array 52 | fn from_bytes_le(bytes : [u8]) -> Self { 53 | // The maximum number of bytes that can fit in this bigint 54 | let MAX_BYTES : comptime Field = NUM_LIMBS * LIMB_BYTES; 55 | let SHIFTS : [comptime u32; 4] = [ 56 | u32_utils::U32_POW_2_0, 57 | u32_utils::U32_POW_2_8, 58 | u32_utils::U32_POW_2_16, 59 | u32_utils::U32_POW_2_24, 60 | ]; 61 | 62 | let bytes_len = std::array::len(bytes) as u32; 63 | 64 | // TODO: Should we allow this? 65 | constrain bytes_len <= MAX_BYTES as u32; 66 | 67 | let mut limbs = [0 as u32; NUM_LIMBS]; 68 | let mut limb : u32 = 0; 69 | for i in 0..MAX_BYTES { 70 | let limb_index = ((i as u8) / 4) as Field; 71 | // i modulo 4 72 | let byte_significance = i - (limb_index * 4); 73 | 74 | if i as u32 < bytes_len { 75 | let mut byte : u32 = bytes[i] as u32; 76 | byte = byte * SHIFTS[byte_significance]; 77 | limb = limb | byte; 78 | } 79 | if byte_significance == 3 { 80 | limbs[limb_index] = limb; 81 | limb = 0; 82 | } 83 | }; 84 | // constrain limbs[0] == 1; 85 | BigInt::new(limbs) 86 | } 87 | 88 | /// Math 89 | 90 | // Returns last non-zero limb, its index, and the limb before it as tuple (msl_index, msl_minus_one, msl). 91 | // Fails if most_significant_limb index < 1. 92 | fn two_most_significant_limbs(self : Self) -> (u32, u32, u32) { 93 | let mut msl_index = 0 as u32; 94 | let mut msl = 0 as u32; 95 | let mut msl_minus_one = 0 as u32; 96 | for i in 0..NUM_LIMBS { 97 | let j = NUM_LIMBS - i - 1; 98 | if (self.limbs[j] > 0) & (msl == 0) { 99 | msl_index = j as u32; 100 | msl = self.limbs[j]; 101 | msl_minus_one = self.limbs[j - 1]; 102 | } 103 | }; 104 | constrain msl_index >= 1; 105 | (msl_index, msl_minus_one, msl) 106 | } 107 | 108 | // Returns last non-zero limb, its index, and the 2 limbs before it as tuple (msl_index, msl_minus_two, msl_minus_one, msl). 109 | // Fails if most_significant_limb index < 2. 110 | fn three_most_significant_limbs(self : Self) -> (u32, u32, u32, u32) { 111 | let mut msl_index = 0 as u32; 112 | let mut msl = 0 as u32; 113 | let mut msl_minus_one = 0 as u32; 114 | let mut msl_minus_two = 0 as u32; 115 | for i in 0..NUM_LIMBS { 116 | let j = NUM_LIMBS - i - 1; 117 | if (self.limbs[j] > 0) & (msl == 0) { 118 | msl_index = j as u32; 119 | msl = self.limbs[j]; 120 | msl_minus_one = self.limbs[j - 1]; 121 | msl_minus_two = self.limbs[j - 2]; 122 | } 123 | }; 124 | constrain msl_index >= 2; 125 | (msl_index, msl_minus_two, msl_minus_one, msl) 126 | } 127 | 128 | // Returns self ^ exponent. 129 | // fn pow(self : Self, exponent : u32) -> Self { 130 | // if self.is_one() | exponent == 0 { 131 | // BigInt::one(); 132 | // } else { 133 | // if self.is_zero() { 134 | // BigInt::zero(); 135 | // } else { 136 | // 137 | // } 138 | // } 139 | // 140 | // } 141 | 142 | // Returns (self ^ exponent) % modulus. 143 | // fn pow_mod(self : Self, exponent : u32, modulus : Self) 144 | 145 | fn add(self : Self, other : BigInt) -> LimbsWithOverflow { 146 | let mut limbs : [u32; NUM_LIMBS] = [0 as u32; NUM_LIMBS]; 147 | let mut carry : u32 = 0; 148 | for i in 0..NUM_LIMBS { 149 | let (limb_sum, new_carry) = arithmetic::add_limbs_with_carry(self.limbs[i], other.limbs[i], carry); 150 | limbs[i] = limb_sum; 151 | carry = new_carry; 152 | }; 153 | LimbsWithOverflow { 154 | limbs: limbs, 155 | overflow: carry, 156 | } 157 | } 158 | 159 | fn mul(self : Self, other : BigInt) -> BigInt2 { 160 | // Double limbs won't overflow because the product of two N-limb arrays is never larger than 2N-limbs 161 | // ((b^n) - 1) * ((b^n) - 1) = b^(2n) - 2(b^n) - 1 < b^(2n) 162 | let mut limbs = [0 as u32; DOUBLE_LIMBS]; 163 | 164 | for i in 0..NUM_LIMBS { 165 | let mut carry : u32 = 0; 166 | for j in 0..NUM_LIMBS { 167 | let k = i + j; 168 | let (limb_product, new_carry) = arithmetic::mul_limbs_with_carry(limbs[k], self.limbs[i], other.limbs[j], carry); 169 | limbs[k] = limb_product; 170 | carry = new_carry; 171 | }; 172 | limbs[i + NUM_LIMBS] = carry; 173 | }; 174 | 175 | BigInt2 { 176 | limbs: limbs, 177 | } 178 | } 179 | 180 | // Returns self + other % modulus. 181 | // fn add_mod(self : Self, other : Self, modulus : Self) 182 | 183 | // Returns self * other % modulus. 184 | // fn mul_mod(self : Self, other : Self, modulus : Self) 185 | 186 | // Returns self - other. 187 | fn sub(self : Self, other : Self) -> LimbsWithOverflow { 188 | let mut limbs : [u32; NUM_LIMBS] = [0 as u32; NUM_LIMBS]; 189 | let mut borrow : u32 = 0; 190 | for i in 0..NUM_LIMBS { 191 | let (limb_diff, new_borrow) = arithmetic::sub_limbs_with_borrow(self.limbs[i], other.limbs[i], borrow); 192 | limbs[i] = limb_diff; 193 | borrow = new_borrow; 194 | }; 195 | 196 | // ToDo: This is a work around because structs in tuples don't work 197 | LimbsWithOverflow { 198 | limbs: limbs, 199 | overflow: borrow, 200 | } 201 | } 202 | 203 | // Returns self - (multiplicand * other). 204 | fn sub_mul(self : Self, multiplicand : u32, other : BigInt) -> LimbsWithOverflow { 205 | let mut limbs : [u32; NUM_LIMBS] = [0 as u32; NUM_LIMBS]; 206 | let mut borrow : u32 = 0; 207 | for i in 0..NUM_LIMBS { 208 | let (limb_diff, new_borrow) = arithmetic::sub_mul_limbs_with_borrow(self.limbs[i], multiplicand, other.limbs[i], borrow); 209 | limbs[i] = limb_diff; 210 | borrow = new_borrow; 211 | }; 212 | 213 | // ToDo: This is a work around because structs in tuples don't work 214 | LimbsWithOverflow { 215 | limbs: limbs, 216 | overflow: borrow, 217 | } 218 | } 219 | 220 | // Returns true iff this number is even. 221 | fn is_even(self : Self) -> bool { 222 | self.limbs[0] % 2 == 0 223 | } 224 | 225 | // Returns true iff this number is odd. 226 | fn is_odd(self : Self) -> bool { 227 | self.limbs[0] % 2 == 1 228 | } 229 | 230 | // Returns true iff all limbs are zero. 231 | fn is_zero(self : Self) -> bool { 232 | let mut result : bool = self.limbs[0] == 0; 233 | for i in 1..NUM_LIMBS { 234 | if result == true { 235 | result = self.limbs[i] == 0; 236 | } 237 | }; 238 | result 239 | } 240 | 241 | // Returns true iff this number is one. 242 | fn is_one(self : Self) -> bool { 243 | let mut result : bool = self.limbs[0] == 1; 244 | for i in 1..NUM_LIMBS { 245 | if result == true { 246 | result = self.limbs[i] == 0; 247 | } 248 | }; 249 | result 250 | } 251 | } 252 | 253 | // /// Excerpted from https://docs.rs/num-bigint/latest/src/num_bigint/biguint/division.rs.html#210 254 | // /// An implementation of the base division algorithm. 255 | // /// Knuth, TAOCP vol 2 section 4.3.1, algorithm D, with an improvement from exercises 19-21. 256 | fn div_rem_core(mut a: BigInt, b: BigInt) -> BigInt { 257 | // TODO: debug_assert!(a.data.len() >= b.len() && b.len() > 1); 258 | // TODO: debug_assert!(b.last().unwrap().leading_zeros() == 0); 259 | 260 | // The algorithm works by incrementally calculating "guesses", q0, for the next digit of the 261 | // quotient. Once we have any number q0 such that (q0 << j) * b <= a, we can set 262 | // 263 | // q += q0 << j 264 | // a -= (q0 << j) * b 265 | // 266 | // and then iterate until a < b. Then, (q, a) will be our desired quotient and remainder. 267 | // 268 | // q0, our guess, is calculated by dividing the last three digits of a by the last two digits of 269 | // b - this will give us a guess that is close to the actual quotient, but is possibly greater. 270 | // It can only be greater by 1 and only in rare cases, with probability at most 271 | // 2^-(big_digit::BITS-1) for random a, see TAOCP 4.3.1 exercise 21. 272 | // 273 | // If the quotient turns out to be too large, we adjust it by 1: 274 | // q -= 1 << j 275 | // a += b << j 276 | 277 | // a0 stores an additional extra most significant digit of the dividend, not stored in a. 278 | let mut a0 = 0 as u32; 279 | let (mut a_msl_index, mut a2, mut a1) = a.two_most_significant_limbs(); 280 | 281 | // [b1, b0] are the two most significant digits of the divisor. They never change. 282 | let (b_msl_index, b1, b0) = b.two_most_significant_limbs(); 283 | 284 | let q_len = a_msl_index - b_msl_index + 1; 285 | let mut q_limbs = [0 as u32; NUM_LIMBS]; 286 | 287 | // TODO: REMOVE 288 | constrain q_limbs[0] == 0; 289 | 290 | for i in 0..NUM_LIMBS { 291 | let j = NUM_LIMBS - i; 292 | if j as u32 < q_len { 293 | // TODO: debug_assert!(a.data.len() == b.len() + j); 294 | // The first q_estimate is [a2,a1,a0] / [b1,b0]. It will never be too small, it may be too large 295 | // by at most 1. 296 | let mut q_estimate = 0 as u32; 297 | let mut r = 0 as u64; 298 | if a0 < b0 { 299 | let result = division::div_wide(a0, a1, a2, b0, b1); 300 | q_estimate = result.0; 301 | r = result.1; 302 | } else { 303 | // TODO: debug_assert!(a0 == b0); 304 | // Avoid overflowing q_estimate 305 | // [a1,a0] = b0 * (1< 0 { 317 | // q_estimate is too large. We need to add back one multiple of b. 318 | q_estimate = q_estimate - 1; 319 | let add_result = a.add(b); 320 | a = BigInt::new(add_result.limbs); 321 | borrow = borrow - add_result.overflow; 322 | } 323 | // The top digit of a, stored in a0, has now been zeroed. 324 | // TODO: debug_assert!(borrow == a0); 325 | 326 | q_limbs[j] = q_estimate; 327 | 328 | // Don't do this on the last iteration when the quotient is fully formed 329 | if j != 0 { 330 | let (a_msl_index_update, a2_update, a1_update, a0_update) = a.three_most_significant_limbs(); 331 | a_msl_index = a_msl_index_update; 332 | a0 = a0_update; 333 | a1 = a1_update; 334 | a2 = a2_update; 335 | } 336 | } 337 | }; 338 | // (BigInt::new(q_limbs), a) 339 | BigInt::new(q_limbs) 340 | } 341 | 342 | 343 | // Tests 344 | fn run_tests() { 345 | arithmetic::run_tests(); 346 | division::run_tests(); 347 | test_from_bytes_be(); 348 | test_is_one_zero(); 349 | test_add(); 350 | test_mul(); 351 | test_sub(); 352 | test_sub_mul(); 353 | test_msl(); 354 | // test_div_rem_core(); 355 | } 356 | 357 | /// from_bytes_be 358 | fn test_from_bytes_be_case1() { 359 | // TODO: this line causes a weird bug that I think is related to MAX_BYTES existing in a diff function 360 | // let MAX_BYTES : comptime Field = NUM_LIMBS * LIMB_BYTES; 361 | let bytes = [1 as u8, 0, 1]; 362 | let bint = BigInt::from_bytes_le(bytes); 363 | constrain bint.limbs[0] == 1 + 65536; 364 | for i in 1..NUM_LIMBS { 365 | constrain bint.limbs[i] == 0; 366 | }; 367 | } 368 | 369 | fn test_from_bytes_be_case2() { 370 | let bytes = [ 371 | 0 as u8, 0, 0, 0, 372 | 0, 0, 0, 7, 373 | ]; 374 | let bint = BigInt::from_bytes_le(bytes); 375 | constrain bint.limbs[0] == 0; 376 | constrain bint.limbs[1] == 117440512; 377 | for i in 2..NUM_LIMBS { 378 | constrain bint.limbs[i] == 0; 379 | }; 380 | } 381 | 382 | fn test_from_bytes_be() { 383 | test_from_bytes_be_case1(); 384 | test_from_bytes_be_case2(); 385 | } 386 | 387 | 388 | // is_zero, is_one 389 | fn test_is_zero_case1() { 390 | let a = BigInt::new([0 as u32; NUM_LIMBS]); 391 | let b = BigInt::new([1 as u32, 0, 0, 0, 0, 0, 0, 0]); 392 | let zero = BigInt::zero(); 393 | constrain a.is_zero() == true; 394 | constrain b.is_zero() == false; 395 | constrain zero.is_zero() == true; 396 | } 397 | 398 | fn test_is_one_case1() { 399 | let a = BigInt::new([0 as u32; NUM_LIMBS]); 400 | let b = BigInt::new([1 as u32, 0, 0, 0, 0, 0, 0, 0]); 401 | let one = BigInt::one(); 402 | constrain a.is_one() == false; 403 | constrain b.is_one() == true; 404 | constrain one.is_one() == true; 405 | } 406 | 407 | fn test_is_one_zero() { 408 | test_is_zero_case1(); 409 | test_is_one_case1(); 410 | } 411 | 412 | 413 | // add 414 | fn test_add_case1() { 415 | let a = BigInt::new([1 as u32; NUM_LIMBS]); 416 | let b = BigInt::new([2 as u32; NUM_LIMBS]); 417 | let expected_sum_limbs = [3 as u32; NUM_LIMBS]; 418 | let expected_overflow = 0; 419 | let result = a.add(b); 420 | constrain result.limbs == expected_sum_limbs; 421 | constrain result.overflow == expected_overflow; 422 | } 423 | 424 | fn test_add_case2() { 425 | let a = BigInt::new([u32_utils::U32_MAX as u32, u32_utils::U32_MAX as u32, u32_utils::U32_MAX as u32, 0, 0, 0, 0, 0]); 426 | let b = BigInt::new([1 as u32, 0, 0, 0, 0, 0, 0, 0]); 427 | let expected_sum_limbs = [0, 0, 0, 1, 0, 0, 0, 0]; 428 | let expected_overflow = 0; 429 | let result = a.add(b); 430 | constrain result.limbs == expected_sum_limbs; 431 | constrain result.overflow == expected_overflow; 432 | } 433 | 434 | fn test_add_case3() { 435 | let a = BigInt::new([u32_utils::U32_MAX as u32; NUM_LIMBS]); 436 | let b = BigInt::new([1 as u32, 0, 0, 0, 0, 0, 0, 0]); 437 | let expected_sum_limbs = [0, 0, 0, 0, 0, 0, 0, 0]; 438 | let expected_overflow = 1; 439 | let result = a.add(b); 440 | constrain result.limbs == expected_sum_limbs; 441 | constrain result.overflow == expected_overflow; 442 | } 443 | 444 | fn test_add() { 445 | test_add_case1(); 446 | test_add_case2(); 447 | test_add_case3(); 448 | } 449 | 450 | 451 | // sub 452 | fn test_sub_case1() { 453 | let a = BigInt::new([3 as u32; NUM_LIMBS]); 454 | let b = BigInt::new([1 as u32; NUM_LIMBS]); 455 | let expected_diff_limbs = [2 as u32; NUM_LIMBS]; 456 | let expected_overflow = 0; 457 | let result = a.sub(b); 458 | constrain result.limbs == expected_diff_limbs; 459 | constrain result.overflow == expected_overflow; 460 | } 461 | 462 | fn test_sub_case2() { 463 | let a = BigInt::new([4 as u32, 2, 0, 0, 0, 0, 0, 0]); 464 | let b = BigInt::new([5 as u32, 0, 0, 0, 0, 0, 0, 0]); 465 | let expected_diff_limbs : [u32; 8] = [u32_utils::U32_MAX as u32, 1, 0, 0, 0, 0, 0, 0]; 466 | let expected_overflow = 0; 467 | let result = a.sub(b); 468 | constrain result.limbs == expected_diff_limbs; 469 | constrain result.overflow == expected_overflow; 470 | } 471 | 472 | fn test_sub_case3() { 473 | let a = BigInt::new([4 as u32, 0, 0, 0, 0, 0, 0, 0]); 474 | let b = BigInt::new([5 as u32, 0, 0, 0, 0, 0, 0, 0]); 475 | let expected_diff_limbs : [u32; 8] = [u32_utils::U32_MAX as u32; 8]; 476 | let expected_overflow = 1; 477 | let result = a.sub(b); 478 | constrain result.limbs == expected_diff_limbs; 479 | constrain result.overflow == expected_overflow; 480 | } 481 | 482 | fn test_sub() { 483 | test_sub_case1(); 484 | test_sub_case2(); 485 | test_sub_case3(); 486 | } 487 | 488 | // mul 489 | fn test_mul_case1() { 490 | let a = BigInt::new([5 as u32, 0, 0, 0, 0, 0, 0, 0]); 491 | let b = BigInt::new([5 as u32, 0, 0, 0, 0, 0, 0, 0]); 492 | let expected_product_limbs = [25 as u32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 493 | let product = a.mul(b); 494 | constrain product.limbs == expected_product_limbs; 495 | } 496 | 497 | fn test_mul_case2() { 498 | let a = BigInt::new([u32_utils::U32_MAX; NUM_LIMBS]); 499 | let b = BigInt::new([u32_utils::U32_MAX; NUM_LIMBS]); 500 | let expected_product_limbs = [1 as u32, 0, 0, 0, 0, 0, 0, 0, 4294967294, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295]; 501 | let product = a.mul(b); 502 | constrain product.limbs == expected_product_limbs; 503 | } 504 | 505 | fn test_mul() { 506 | test_mul_case1(); 507 | test_mul_case2(); 508 | } 509 | 510 | 511 | // sub_mul 512 | fn test_sub_mul_case1() { 513 | let a = BigInt::new([u32_utils::U32_MAX, u32_utils::U32_MAX, u32_utils::U32_MAX, 0, 0, 0, 0, 0]); 514 | let b = u32_utils::U32_MAX; 515 | let c = BigInt::new([u32_utils::U32_MAX, u32_utils::U32_MAX, 0, 0, 0, 0, 0, 0]); 516 | let expected_product_limbs : [u32; 8] = [u32_utils::U32_MAX - 1, 0, 1, 0, 0, 0, 0, 0]; 517 | let product = a.sub_mul(b, c); 518 | constrain product.limbs == expected_product_limbs; 519 | } 520 | 521 | fn test_sub_mul() { 522 | test_sub_mul_case1(); 523 | } 524 | 525 | 526 | // msl 527 | fn test_msl_case1() { 528 | let a = BigInt::new([u32_utils::U32_MAX, u32_utils::U32_MAX, u32_utils::U32_MAX, 0, 0, 0, 0, 0]); 529 | let expected_msl_index = 2; 530 | let expected_msl : u32 = a.limbs[2]; 531 | let expected_msl_minus_one = a.limbs[1]; 532 | let (msl_index, msl_minus_one , msl) = a.two_most_significant_limbs(); 533 | constrain expected_msl_index == msl_index; 534 | constrain expected_msl == msl; 535 | constrain expected_msl_minus_one == msl_minus_one; 536 | } 537 | 538 | fn test_msl_case2() { 539 | let a = BigInt::new([u32_utils::U32_MAX, u32_utils::U32_MAX, u32_utils::U32_MAX, 0, 0, 0, 0, 1]); 540 | let expected_msl_index = 7; 541 | let expected_msl : u32 = 1; 542 | let expected_msl_minus_one = 0; 543 | let (msl_index, msl_minus_one , msl) = a.two_most_significant_limbs(); 544 | constrain expected_msl_index == msl_index; 545 | constrain expected_msl == msl; 546 | constrain expected_msl_minus_one == msl_minus_one; 547 | } 548 | 549 | fn test_msl_case3() { 550 | let a = BigInt::new([0, 0, 100, 0, 1, 0, 0, 0]); 551 | let expected_msl_index = 4; 552 | let expected_msl : u32 = 1; 553 | let expected_msl_minus_one = 0; 554 | let expected_msl_minus_two = 100; 555 | let (msl_index, msl_minus_two, msl_minus_one , msl) = a.three_most_significant_limbs(); 556 | constrain expected_msl_index == msl_index; 557 | constrain expected_msl == msl; 558 | constrain expected_msl_minus_one == msl_minus_one; 559 | constrain expected_msl_minus_two == msl_minus_two; 560 | } 561 | 562 | fn test_msl_case4() { 563 | let a = BigInt::new([1, 2, 3, 0, 0, 0, 0, 0]); 564 | let expected_msl_index = 2; 565 | let expected_msl : u32 = 3; 566 | let expected_msl_minus_one = 2; 567 | let expected_msl_minus_two = 1; 568 | let (msl_index, msl_minus_two, msl_minus_one , msl) = a.three_most_significant_limbs(); 569 | constrain expected_msl_index == msl_index; 570 | constrain expected_msl == msl; 571 | constrain expected_msl_minus_one == msl_minus_one; 572 | constrain expected_msl_minus_two == msl_minus_two; 573 | } 574 | 575 | fn test_msl() { 576 | test_msl_case1(); 577 | test_msl_case2(); 578 | test_msl_case3(); 579 | test_msl_case4(); 580 | } 581 | 582 | 583 | // div_rem_core 584 | fn test_div_rem_core_case1() { 585 | let a = BigInt::new([0, 0, 0, 0, 1, 0, 0, 0]); 586 | let b = BigInt::new([9, 9, 1, 0, 0, 0, 0, 0]); 587 | // let expected_product_limbs : [u32; 8] = [u32_utils::U32_MAX - 1, 0, 1, 0, 0, 0, 0, 0]; 588 | let q = div_rem_core(a, b); 589 | constrain q.limbs[0] != 1; 590 | } 591 | 592 | fn test_div_rem_core() { 593 | test_div_rem_core_case1(); 594 | } --------------------------------------------------------------------------------