BEGIN; SELECT plan(14); SELECT lives_ok($$select crypto_sign_seed_new_keypair(crypto_sign_new_seed())$$, 'crypto_sign_seed_new_keypair'); SELECT throws_ok($$select crypto_sign_seed_new_keypair('bogus')$$, '22000', 'invalid seed', 'crypto_sign_seed_new_keypair invalid seed'); SELECT public, secret FROM crypto_sign_new_keypair() \gset sign_ SELECT crypto_sign('bob is your uncle', :'sign_secret') signed \gset SELECT throws_ok($$select crypto_sign('bob is your uncle', 's')$$, '22000', 'invalid secret key', 'crypto_sign invalid key'); SELECT is(crypto_sign_open(:'signed', :'sign_public'), 'bob is your uncle', 'crypto_sign_open'); SELECT throws_ok(format($$select crypto_sign_open(%L, 'bad_key')$$, :'signed'), '22000', 'invalid public key', 'crypto_sign_open invalid public key'); SELECT throws_ok(format($$select crypto_sign_open('foo', %L)$$, :'sign_public'), '22000', 'invalid message', 'crypto_sign_open invalid message'); -- public key signatures -- We will sign our previously generated sealed box SELECT throws_ok($$select crypto_sign_detached('foo', 'bar')$$, '22000', 'invalid secret key', 'crypto_sign_detached invalid secret key'); SELECT throws_ok($$select crypto_sign_verify_detached('foo', 'bar', 'bork')$$, '22000', 'invalid public key', 'crypto_sign_verify_detached invalid public key'); SELECT crypto_sign_detached('sealed message', :'sign_secret') detached \gset SELECT is(crypto_sign_verify_detached(:'detached', 'sealed message', :'sign_public'), true, 'crypto_sign_detached/verify'); SELECT is(crypto_sign_verify_detached(:'detached', 'xyzzy', :'sign_public'), false, 'crypto_sign_detached/verify (incorrect message)'); -- Check Multi-part messages WITH parts(msg) AS ( VALUES ('Hello Alice'), ('Hello Bob'), ('Hello Carol') ), tampered(msg) AS ( VALUES ('Hello Alice'), ('Hello Bob'), ('Hello CaRol') ), prep1 AS ( -- First form of aggregate SELECT crypto_sign_update_agg(p.msg::bytea) state FROM parts p ), prep2 AS ( -- Second form of aggregate SELECT crypto_sign_update_agg(crypto_sign_init(), p.msg::bytea) state FROM parts p ), prepv AS ( -- Second form of aggregate from tampered parts SELECT crypto_sign_update_agg(crypto_sign_init(), t.msg::bytea) state FROM tampered t ), sig AS ( SELECT crypto_sign_final_create(p.state, :'sign_secret') as sig FROM prep1 p ), verify AS ( SELECT crypto_sign_final_verify(p.state, s.sig, :'sign_public') as verify FROM prep1 p CROSS JOIN sig s ), verify2 AS ( SELECT crypto_sign_final_verify(p.state, s.sig, :'sign_public') as verify FROM prep2 p CROSS JOIN sig s ), noverify AS ( SELECT crypto_sign_final_verify(p.state, s.sig, :'sign_public') as verify FROM prepv p CROSS JOIN sig s ) SELECT ok(verify, 'Multi-part signature') FROM verify UNION ALL SELECT ok(verify, 'Multi-part signature(2)') FROM verify2 UNION ALL -- Each time we generate state it will be different, even though sig -- can be verified. SELECT isnt(p1.state, p2.state, 'Multi-part states differ') FROM prep1 p1 CROSS JOIN prep2 p2 UNION ALL SELECT ok(not verify, 'Multi-part signature detects tampering') FROM noverify; SELECT * FROM finish(); ROLLBACK;