index.html

README.txt

Code for hello-parigp.sh:

#!/bin/sh
# https://github.com/ctarbide/coolscripts/blob/master/examples/dosbox-hello.sh
set -eu
thispath=`perl -MFile::Spec::Functions=rel2abs,canonpath -le'print(canonpath(rel2abs(\$ARGV[0])))' -- "${0}"`
set -- "${thispath}" --ba-- "${thispath}" "$@" --ea--
set -- "$@" --tmp-- .nw
SH=${SH:-sh -eu}; export SH
[ x"${ZSH_VERSION:-}" = x ] || setopt sh_word_split
GP=${GP:-gp -fq}; export GP
exec nofake-exec.sh --error -Rprog "$@" -- ${SH}
exit 1

****************

params:

           z  0xd52302b96d2fe527341fc786f8013609e821c10be410a3a2594c5c6498b96c3e (message hash)
   public key 0x78d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 (x)
              0xa1518063243acd4dfe96b66e3f2ec8013c8e072cd09b3834a19f81f659cc3455 (y)
        sig r 0x194e04717bebcd8cf96b90dab7d8c75776e043f3b323c6535a04bff992a3172c
        sig s 0x0c432b1e920729db1a83c54590263038349bae040921754cd33f21ef14a7df3d

<<call it>>=
{
    z = 0xa2c5acf76bc96cd474884befefebbe483fd16ed8c00741f2a0bc84051d507061; \\ verifier (hash)
    r = 0x194e04717bebcd8cf96b90dab7d8c75776e043f3b323c6535a04bff992a3172c; \\ sig-r
    s = 0x0c432b1e920729db1a83c54590263038349bae040921754cd33f21ef14a7df3d; \\ sig-s
    Qx = 0x78d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71; \\ pubkey x, want y odd

    Q = decompress_pubkey(3 /* y is odd */, Qx);
    if(Qx != Q[1], error("Qx != Q[1]"));

    if(!ellisoncurve(E, Q), error('not on curve'));

    print(strprintf("x=0x%064x", Q[1]));
    print(strprintf("y=0x%064x", Q[2]));
    print(strprintf("z=0x%064x", z));
    print(strprintf("r=0x%064x", r));
    print(strprintf("s=0x%064x", s));

    print("success? ", if(verify_ecdsa(z, r, s, Q) == 1, "yes", "no"));
}
@

****************

<<prog>>=
<<prog preamble>>
#@<<prog cwd>>
<<prog thisdir>>
<<setnw common>>
set -- --ba-- "$@" --ea-- "${thispath}" "${0}.nw"
exec nofake-exec.sh --error -Rdoit "$@" -- ${SH}
@

****************

'pwd' cleans the path from '..' elements

<<prog cwd>>=
thisdir=`cd "${thisdir}" && pwd`
setnw CWD "`pwd`"
@

<<prog thisdir>>=
cd "${thisdir}"
thisdir=`pwd`
setnw CWD "${thisdir}"
@

<<prog preamble>>=
<<function die>>
<<function setnw>>
thispath=${1}; shift
thisprog=${thispath##*/}
thisdir=${thispath%/*}
@

<<setnw common>>=
setnw AUXNW "${0}.nw"
setnw THISPATH "${thispath}"
setnw THISPROG "${thisprog}"
setnw THISDIR "${thisdir}"
setnw MAIN_PID "$$"
stamp=`date '+%Y-%m-%d_%Hh%Mm%S'`
setnw STAMP "${stamp}"
thisdirbasename=${thisdir##*/}
setnw THISDIRBASENAME "${thisdirbasename}"
@

****************

<<function die>>=
die(){ ev=$1; shift; for msg in "$@"; do echo "${msg}"; done; exit "${ev}"; }
@

<<function setnw>>=
setnw(){ printf -- '@<<%s>>=\n%s\n@\n' "${1}" "${2}" >>"${0}.nw"; }
@

****************

<<doit>>=
set -- --ba-- "$@" --ea-- '<<THISPATH>>' '<<AUXNW>>'
exec nofake-exec.sh --error -R'gp script' "$@" -- ${GP}
@

****************

<<gp script>>=
<<curve params>>
<<decompress_pubkey function>>
<<verify_ecdsa function>>
<<call it>>
\quit
@

**************** secp256k1 params

openssl ecparam -param_enc explicit -conv_form compressed -text -noout -no_seed -name secp256k1 >secp256k1-params-c.txt
openssl ecparam -param_enc explicit -conv_form uncompressed -text -noout -no_seed -name secp256k1 >secp256k1-params-u.txt

<<curve params>>=
\\ Prime modulus
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
\\ Curve coefficients [a, b] for y^2 = x^3 + ax + b
a = 0; b = 7;
\\ Initialize curve
E = ellinit([a, b], p);
\\ Base point G (Generator)
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
G = [Gx, Gy];
\\ Order of the group generated by G
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
@

****************

<<decompress_pubkey function>>=
\\ prefix: 2 or 3
decompress_pubkey(prefix, x) =
{
    my(y2, y0, y0_is_even, want_even_y, y);

    if (prefix != 2 && prefix != 3,
        error("invalid compressed pubkey prefix"));

    x = lift(Mod(x, p)); \\ normalize
    if (x < 0 || x >= p,
        error("x not in canonical range"));

    y2 = Mod(x^3 + E.a4*x + E.a6, p);
    y0 = lift(sqrt(y2)); \\ modular sqrt, may throw (good)
    y0_is_even = y0 % 2 == 0;
    want_even_y = (prefix == 2);
    if (y0_is_even == want_even_y,
        y = y0,
        y = p - y0); \\ negate y0

    y = lift(Mod(y, p)); \\ normalize
    return([x, y]);
}
@

****************

<<verify_ecdsa function>>=
verify_ecdsa(z, r, s, Q) =
{
    my(w, u1, u2, Ra, Rb, R, r_prime);

    \\ n is the group order
    if(r <= 0 || r >= n || s <= 0 || s >= n, error("r or s out of range"));

    w = lift(Mod(1/s, n));    \\ w = s⁻¹ (mod n);
    u1 = lift(Mod(z * w, n)); \\ u₁ = z · w (mod n)
    u2 = lift(Mod(r * w, n)); \\ u₂ = r · w (mod n)

    Ra = ellmul(E, G, u1); \\ u₁·G
    Rb = ellmul(E, Q, u2); \\ u₂·Q
    R = elladd(E, Ra, Rb); \\ R = u₁·G + u₂·Q

    if(R[1] == 0 && R[2] == 0,
        error("point at infinity"));

    r_prime = lift(R[1]) % n;

    return(r_prime == r);
}
@

****************